opencode-navigator 0.27.1 → 0.27.2

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.
@@ -2718,6 +2718,16 @@ function targetForLegacyScope(scope) {
2718
2718
  key: scope
2719
2719
  };
2720
2720
  }
2721
+ // src/shared/lib/reorder.ts
2722
+ function reorderItems(items, from, to, key) {
2723
+ const source = items.findIndex((item) => key(item) === from);
2724
+ const target = items.findIndex((item) => key(item) === to);
2725
+ const next = [...items];
2726
+ if (source === -1 || target === -1 || source === target) return next;
2727
+ const [item] = next.splice(source, 1);
2728
+ next.splice(target, 0, item);
2729
+ return next;
2730
+ }
2721
2731
  // src/entities/preferences/model/built-ins.ts
2722
2732
  function builtInPreferences(defaults) {
2723
2733
  return {
@@ -3354,6 +3364,14 @@ function createPreferencesModel(ports, defaults, store, configuredInput = {}) {
3354
3364
  behavior: { quickActionOrder: order }
3355
3365
  });
3356
3366
  },
3367
+ reorderQuickAction(from, to, scope) {
3368
+ if (scope !== targetKey(selectedTarget())) return;
3369
+ const order = reorderItems(selectedResolved().behavior.quickActionOrder, from, to, (id) => id);
3370
+ update({
3371
+ target: selectedTarget(),
3372
+ behavior: { quickActionOrder: order }
3373
+ });
3374
+ },
3357
3375
  sectionItemLimit: (section) => resolved().behavior.sectionItemLimits[section] ?? 0,
3358
3376
  selectedSectionItemLimit: (section) => selectedResolved().behavior.sectionItemLimits[section] ?? 0,
3359
3377
  setSectionItemLimit(section, value) {
@@ -3579,6 +3597,11 @@ function createPreferencesModel(ports, defaults, store, configuredInput = {}) {
3579
3597
  swap(order, index, destination);
3580
3598
  setSelectedSessionLayout({ order });
3581
3599
  },
3600
+ reorderSelectedSection(from, to, scope) {
3601
+ if (scope !== targetKey(selectedTarget())) return;
3602
+ const layout = resolveTarget(selectedTarget()).layout;
3603
+ setSelectedSessionLayout({ order: reorderItems(layout.order, from, to, (id) => id) });
3604
+ },
3582
3605
  previewLayoutPreset(preset) {
3583
3606
  return layoutPresetPreview(selectedLayoutResolved().layout, preset);
3584
3607
  },
@@ -3876,10 +3899,16 @@ function sourceIdentity(item) {
3876
3899
  version: item.source.version
3877
3900
  } : item?.source);
3878
3901
  }
3879
- function createMainPluginUpdate(context) {
3902
+ function createMainPluginUpdate(context, changed = () => {}) {
3880
3903
  let prepared;
3881
3904
  let busy = false;
3905
+ let phase = "idle";
3906
+ const report = (next) => {
3907
+ phase = next;
3908
+ changed();
3909
+ };
3882
3910
  return {
3911
+ state: () => ({ phase }),
3883
3912
  async check(_input, caller) {
3884
3913
  if (busy) throw new Error("Navigator installation is already in progress");
3885
3914
  prepared = void 0;
@@ -3921,6 +3950,7 @@ function createMainPluginUpdate(context) {
3921
3950
  async install(input, caller) {
3922
3951
  if (busy || !prepared || input.token !== prepared.token) throw new Error("Update confirmation expired. Check again.");
3923
3952
  busy = true;
3953
+ report("preparing");
3924
3954
  const expected = prepared;
3925
3955
  prepared = void 0;
3926
3956
  try {
@@ -3933,12 +3963,14 @@ function createMainPluginUpdate(context) {
3933
3963
  const response = await client.plugin.list({}, { signal });
3934
3964
  const item = response.data.find((entry) => entry.id === context.id);
3935
3965
  if (context.client !== client || sourceIdentity(item) !== expected.source || packageTarget(item) !== expected.target) throw new Error("Navigator installation changed. Check again before installing.");
3966
+ report("installing");
3936
3967
  await client.plugin.update({
3937
3968
  location: response.location,
3938
3969
  targets: [expected.target]
3939
3970
  }, { signal });
3940
3971
  } finally {
3941
3972
  busy = false;
3973
+ report("idle");
3942
3974
  }
3943
3975
  }
3944
3976
  };
@@ -4646,6 +4678,13 @@ function localCodexIpc(pluginID) {
4646
4678
  function pluginUpdateIpc(pluginID) {
4647
4679
  return _opencode_plugin_gui.Ipc.define({
4648
4680
  id: `${pluginID}.package-update`,
4681
+ state: effect.Schema.Struct({ phase: effect.Schema.Literals([
4682
+ "idle",
4683
+ "preparing",
4684
+ "downloading",
4685
+ "installing",
4686
+ "verifying"
4687
+ ]) }),
4649
4688
  methods: {
4650
4689
  check: { output: effect.Schema.Struct({
4651
4690
  status: effect.Schema.Literals([
@@ -4675,14 +4714,15 @@ function preferencesIpc(pluginID) {
4675
4714
  var main = (context) => {
4676
4715
  const store = desktopPreferencesStore();
4677
4716
  const readAccount = createMainAccountReader(context);
4678
- const codex = createNodeCodexClient({ version: "0.27.1" });
4717
+ const codex = createNodeCodexClient({ version: "0.27.2" });
4679
4718
  context.onCleanup(codex.dispose);
4680
4719
  context.provide(preferencesIpc(context.id), createMainPreferencesHandlers(store));
4681
4720
  context.provide(localAccountIpc(context.id), { read: readAccount });
4682
4721
  context.provide(localCodexIpc(context.id), createMainCodexHandlers(context, store, codex));
4683
- context.provide(pluginUpdateIpc(context.id), createMainPluginUpdate(context));
4722
+ const updateImpl = createMainPluginUpdate(context, () => updateProvider.changed());
4723
+ const updateProvider = context.provide(pluginUpdateIpc(context.id), updateImpl);
4684
4724
  context.provide(bugReportIpc(context.id), createMainBugReport(context.signal));
4685
- context.log.write("info", `Navigator 0.27.1 Desktop main ready`);
4725
+ context.log.write("info", `Navigator 0.27.2 Desktop main ready`);
4686
4726
  };
4687
4727
  // src/pages/navigator/ui/gui/context.tsx
4688
4728
  var NavigatorGuiContext = (0, solid_js.createContext)();
@@ -4692,11 +4732,11 @@ function useNavigatorGui() {
4692
4732
  return services;
4693
4733
  }
4694
4734
  // src/pages/navigator/ui/gui/bookmark.tsx
4695
- var _tmpl$$55 = /*#__PURE__*/ (0, solid_js_web.template)(`<span style=width:24px;flex-shrink:0><button type=button style=width:24px;height:24px;padding:0;display:inline-flex;align-items:center;justify-content:center;border:0;border-radius:4px;color:inherit><svg width=12 height=16 viewBox="0 0 14 18"aria-hidden=true><path d="M3 2H11V15L7 12L3 15Z"stroke=currentColor stroke-width=1.5>`);
4735
+ var _tmpl$$60 = /*#__PURE__*/ (0, solid_js_web.template)(`<span style=width:24px;flex-shrink:0><button type=button style=width:24px;height:24px;padding:0;display:inline-flex;align-items:center;justify-content:center;border:0;border-radius:4px;color:inherit><svg width=12 height=16 viewBox="0 0 14 18"aria-hidden=true><path d="M3 2H11V15L7 12L3 15Z"stroke=currentColor stroke-width=1.5>`);
4696
4736
  function SidebarBookmark(props) {
4697
4737
  const label = () => `${props.selected ? "Unbookmark" : "Bookmark"} ${props.title}`;
4698
4738
  return (() => {
4699
- var _el$ = _tmpl$$55(), _el$2 = _el$.firstChild, _el$4 = _el$2.firstChild.firstChild;
4739
+ var _el$ = _tmpl$$60(), _el$2 = _el$.firstChild, _el$4 = _el$2.firstChild.firstChild;
4700
4740
  _el$2.$$click = (event) => {
4701
4741
  event.stopPropagation();
4702
4742
  props.toggle();
@@ -4725,7 +4765,7 @@ function SidebarBookmark(props) {
4725
4765
  }
4726
4766
  (0, solid_js_web.delegateEvents)(["click"]);
4727
4767
  // src/pages/navigator/ui/gui/catalog-row.tsx
4728
- var _tmpl$$54 = /*#__PURE__*/ (0, solid_js_web.template)(`<li style="display:flex;gap:4px;align-items:center;min-width:0;padding:3px 0"><button type=button style=flex:1;min-width:0;display:flex;gap:6px;align-items:center;text-align:left;padding:4px;color:inherit;border:0;border-radius:6px><span style=min-width:0;flex:1><span style=display:block;overflow-wrap:anywhere></span><span style=display:block;opacity:0.65;font-size:12px;overflow-wrap:anywhere>`);
4768
+ var _tmpl$$59 = /*#__PURE__*/ (0, solid_js_web.template)(`<li style="display:flex;gap:4px;align-items:center;min-width:0;padding:3px 0"><button type=button style=flex:1;min-width:0;display:flex;gap:6px;align-items:center;text-align:left;padding:4px;color:inherit;border:0;border-radius:6px><span style=min-width:0;flex:1><span style=display:block;overflow-wrap:anywhere></span><span style=display:block;opacity:0.65;font-size:12px;overflow-wrap:anywhere>`);
4729
4769
  function navigate$1(event) {
4730
4770
  if (event.key !== "ArrowLeft" && event.key !== "ArrowRight") return;
4731
4771
  const buttons = [...event.currentTarget.querySelectorAll("button:not(:disabled)")];
@@ -4740,7 +4780,7 @@ function CatalogRow(props) {
4740
4780
  const [hovered, setHovered] = (0, solid_js.createSignal)(false);
4741
4781
  const [focused, setFocused] = (0, solid_js.createSignal)(false);
4742
4782
  return (() => {
4743
- var _el$ = _tmpl$$54(), _el$2 = _el$.firstChild, _el$3 = _el$2.firstChild, _el$4 = _el$3.firstChild, _el$5 = _el$4.nextSibling;
4783
+ var _el$ = _tmpl$$59(), _el$2 = _el$.firstChild, _el$3 = _el$2.firstChild, _el$4 = _el$3.firstChild, _el$5 = _el$4.nextSibling;
4744
4784
  _el$.$$keydown = navigate$1;
4745
4785
  _el$.$$focusout = (event) => {
4746
4786
  if (!event.currentTarget.contains(event.relatedTarget)) setFocused(false);
@@ -4842,15 +4882,19 @@ function GuiActionRow(props) {
4842
4882
  });
4843
4883
  }
4844
4884
  // src/pages/navigator/ui/gui/section.tsx
4845
- var _tmpl$$53 = /*#__PURE__*/ (0, solid_js_web.template)(`<section style=min-width:0><div style=display:flex;gap:8px;align-items:center;min-width:0><h2 style=flex:1;min-width:0;font-size:13px;font-weight:600;margin:0><button type=button style="display:flex;gap:6px;align-items:center;width:100%;padding:3px 0;color:inherit;background:transparent;border:0;text-align:left"><span aria-hidden=true></span><span style=overflow:hidden;text-overflow:ellipsis;white-space:nowrap></span><span style=opacity:0.55;font-weight:400>`);
4885
+ var _tmpl$$58 = /*#__PURE__*/ (0, solid_js_web.template)(`<section style=min-width:0><div style=display:flex;gap:8px;align-items:center;min-width:0><h2 style=flex:1;min-width:0;font-size:13px;font-weight:600;margin:0><button type=button style="display:flex;gap:6px;align-items:center;width:100%;padding:3px 0;color:inherit;background:transparent;border:0;text-align:left"><span aria-hidden=true data-navigator-disclosure style=display:inline-flex;width:16px;height:16px;flex-shrink:0;align-items:center;justify-content:center></span><span style=overflow:hidden;text-overflow:ellipsis;white-space:nowrap></span><span style=opacity:0.55;font-weight:400>`);
4846
4886
  function MonitoringSection(props) {
4847
4887
  const services = useNavigatorGui();
4848
4888
  const preferences = () => services.runtime.catalogs?.preferences;
4849
4889
  const expanded = () => preferences()?.expanded()[props.id] ?? true;
4890
+ const Icon = services.ui.Icon;
4850
4891
  return (() => {
4851
- var _el$ = _tmpl$$53(), _el$2 = _el$.firstChild, _el$4 = _el$2.firstChild.firstChild, _el$5 = _el$4.firstChild, _el$6 = _el$5.nextSibling, _el$7 = _el$6.nextSibling;
4892
+ var _el$ = _tmpl$$58(), _el$2 = _el$.firstChild, _el$4 = _el$2.firstChild.firstChild, _el$5 = _el$4.firstChild, _el$6 = _el$5.nextSibling, _el$7 = _el$6.nextSibling;
4852
4893
  _el$4.$$click = () => preferences()?.toggleSectionExpanded(props.id);
4853
- (0, solid_js_web.insert)(_el$5, () => expanded() ? "⌄" : "›");
4894
+ (0, solid_js_web.insert)(_el$5, (0, solid_js_web.createComponent)(Icon, {
4895
+ name: "chevron-down",
4896
+ size: "small"
4897
+ }));
4854
4898
  (0, solid_js_web.insert)(_el$6, () => props.title);
4855
4899
  (0, solid_js_web.insert)(_el$7, () => props.count);
4856
4900
  (0, solid_js_web.insert)(_el$2, () => props.actions, null);
@@ -4863,24 +4907,26 @@ function MonitoringSection(props) {
4863
4907
  }
4864
4908
  }), null);
4865
4909
  (0, solid_js_web.effect)((_p$) => {
4866
- var _v$ = props.title, _v$2 = expanded();
4910
+ var _v$ = props.title, _v$2 = expanded(), _v$3 = expanded() ? "rotate(0deg)" : "rotate(-90deg)";
4867
4911
  _v$ !== _p$.e && (0, solid_js_web.setAttribute)(_el$, "aria-label", _p$.e = _v$);
4868
4912
  _v$2 !== _p$.t && (0, solid_js_web.setAttribute)(_el$4, "aria-expanded", _p$.t = _v$2);
4913
+ _v$3 !== _p$.a && (0, solid_js_web.setStyleProperty)(_el$5, "transform", _p$.a = _v$3);
4869
4914
  return _p$;
4870
4915
  }, {
4871
4916
  e: void 0,
4872
- t: void 0
4917
+ t: void 0,
4918
+ a: void 0
4873
4919
  });
4874
4920
  return _el$;
4875
4921
  })();
4876
4922
  }
4877
4923
  (0, solid_js_web.delegateEvents)(["click"]);
4878
4924
  // src/pages/navigator/ui/gui/section-filter.tsx
4879
- var _tmpl$$52 = /*#__PURE__*/ (0, solid_js_web.template)(`<div style="margin:8px 0">`);
4925
+ var _tmpl$$57 = /*#__PURE__*/ (0, solid_js_web.template)(`<div style="margin:8px 0">`);
4880
4926
  function SectionFilter(props) {
4881
4927
  const TextInput = useNavigatorGui().ui.TextInput;
4882
4928
  return (() => {
4883
- var _el$ = _tmpl$$52();
4929
+ var _el$ = _tmpl$$57();
4884
4930
  (0, solid_js_web.insert)(_el$, (0, solid_js_web.createComponent)(TextInput, {
4885
4931
  get label() {
4886
4932
  return props.label;
@@ -4900,9 +4946,9 @@ function SectionFilter(props) {
4900
4946
  })();
4901
4947
  }
4902
4948
  // src/pages/navigator/ui/gui/actions-section.tsx
4903
- var _tmpl$$51 = /*#__PURE__*/ (0, solid_js_web.template)(`<p style=opacity:0.65>No matching actions.`);
4904
- var _tmpl$2$34 = /*#__PURE__*/ (0, solid_js_web.template)(`<div style=display:flex;flex-direction:column;gap:12px>`);
4905
- var _tmpl$3$21 = /*#__PURE__*/ (0, solid_js_web.template)(`<ul style=margin:0;padding:0;list-style:none>`);
4949
+ var _tmpl$$56 = /*#__PURE__*/ (0, solid_js_web.template)(`<p style=opacity:0.65>No matching actions.`);
4950
+ var _tmpl$2$38 = /*#__PURE__*/ (0, solid_js_web.template)(`<div style=display:flex;flex-direction:column;gap:12px>`);
4951
+ var _tmpl$3$24 = /*#__PURE__*/ (0, solid_js_web.template)(`<ul style=margin:0;padding:0;list-style:none>`);
4906
4952
  function ActionsSection() {
4907
4953
  const services = useNavigatorGui();
4908
4954
  const catalogs = () => services.runtime.catalogs;
@@ -4927,13 +4973,13 @@ function ActionsSection() {
4927
4973
  }
4928
4974
  }),
4929
4975
  (() => {
4930
- var _el$ = _tmpl$2$34();
4976
+ var _el$ = _tmpl$2$38();
4931
4977
  (0, solid_js_web.insert)(_el$, (0, solid_js_web.createComponent)(solid_js.For, {
4932
4978
  get each() {
4933
4979
  return [true, false].filter((selected) => view().visibility.visible().some((id) => catalogs().preferences.favoriteQuickActions().has(id) === selected));
4934
4980
  },
4935
4981
  children: (selected) => (() => {
4936
- var _el$3 = _tmpl$3$21();
4982
+ var _el$3 = _tmpl$3$24();
4937
4983
  (0, solid_js_web.insert)(_el$3, (0, solid_js_web.createComponent)(solid_js.For, {
4938
4984
  get each() {
4939
4985
  return view().visibility.visible().filter((id) => catalogs().preferences.favoriteQuickActions().has(id) === selected);
@@ -4948,7 +4994,7 @@ function ActionsSection() {
4948
4994
  return view().filtered().length === 0;
4949
4995
  },
4950
4996
  get children() {
4951
- return _tmpl$$51();
4997
+ return _tmpl$$56();
4952
4998
  }
4953
4999
  }), null);
4954
5000
  return _el$;
@@ -4973,11 +5019,11 @@ function ActionsSection() {
4973
5019
  });
4974
5020
  }
4975
5021
  // src/pages/navigator/ui/gui/quota-window.tsx
4976
- var _tmpl$$50 = /*#__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>`);
5022
+ var _tmpl$$55 = /*#__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>`);
4977
5023
  function GuiQuotaWindow(props) {
4978
5024
  const view = () => quotaPresentation(props.window);
4979
5025
  return (() => {
4980
- var _el$ = _tmpl$$50(), _el$2 = _el$.firstChild, _el$3 = _el$2.firstChild, _el$5 = _el$2.nextSibling.firstChild, _el$6 = _el$5.nextSibling;
5026
+ var _el$ = _tmpl$$55(), _el$2 = _el$.firstChild, _el$3 = _el$2.firstChild, _el$5 = _el$2.nextSibling.firstChild, _el$6 = _el$5.nextSibling;
4981
5027
  (0, solid_js_web.insert)(_el$5, () => view().reset);
4982
5028
  (0, solid_js_web.insert)(_el$6, () => view().value);
4983
5029
  (0, solid_js_web.effect)((_p$) => {
@@ -4999,10 +5045,9 @@ function GuiQuotaWindow(props) {
4999
5045
  })();
5000
5046
  }
5001
5047
  // src/pages/navigator/ui/gui/limits-section.tsx
5002
- var _tmpl$$49 = /*#__PURE__*/ (0, solid_js_web.template)(`<div style=display:flex;gap:4px;align-items:center;min-width:0>`);
5003
- var _tmpl$2$33 = /*#__PURE__*/ (0, solid_js_web.template)(`<p role=alert>`);
5004
- var _tmpl$3$20 = /*#__PURE__*/ (0, solid_js_web.template)(`<p style=opacity:0.65>`);
5005
- var _tmpl$4$12 = /*#__PURE__*/ (0, solid_js_web.template)(`<p>: `);
5048
+ var _tmpl$$54 = /*#__PURE__*/ (0, solid_js_web.template)(`<p role=alert>`);
5049
+ var _tmpl$2$37 = /*#__PURE__*/ (0, solid_js_web.template)(`<p style=opacity:0.65>`);
5050
+ var _tmpl$3$23 = /*#__PURE__*/ (0, solid_js_web.template)(`<p>: `);
5006
5051
  function LimitsSection() {
5007
5052
  const props = useNavigatorGui();
5008
5053
  const limits = () => props.runtime.limits;
@@ -5047,31 +5092,6 @@ function LimitsSection() {
5047
5092
  },
5048
5093
  get children() {
5049
5094
  return [
5050
- (() => {
5051
- var _el$ = _tmpl$$49();
5052
- (0, solid_js_web.insert)(_el$, (0, solid_js_web.createComponent)(Button, {
5053
- size: "small",
5054
- variant: "ghost",
5055
- onClick: () => limits()?.chooseModel(),
5056
- get children() {
5057
- return limits()?.label() ?? "Select model";
5058
- }
5059
- }), null);
5060
- (0, solid_js_web.insert)(_el$, (0, solid_js_web.createComponent)(solid_js.Show, {
5061
- get when() {
5062
- return limits()?.selected()?.variant;
5063
- },
5064
- children: (variant) => (0, solid_js_web.createComponent)(Button, {
5065
- size: "small",
5066
- variant: "ghost-muted",
5067
- onClick: () => limits()?.chooseVariant(),
5068
- get children() {
5069
- return variant();
5070
- }
5071
- })
5072
- }), null);
5073
- return _el$;
5074
- })(),
5075
5095
  (0, solid_js_web.createComponent)(solid_js.Show, {
5076
5096
  get when() {
5077
5097
  return canLink();
@@ -5092,9 +5112,9 @@ function LimitsSection() {
5092
5112
  return state()?.error;
5093
5113
  },
5094
5114
  get children() {
5095
- var _el$2 = _tmpl$2$33();
5096
- (0, solid_js_web.insert)(_el$2, () => state()?.error?.message);
5097
- return _el$2;
5115
+ var _el$ = _tmpl$$54();
5116
+ (0, solid_js_web.insert)(_el$, () => state()?.error?.message);
5117
+ return _el$;
5098
5118
  }
5099
5119
  }),
5100
5120
  (0, solid_js_web.createComponent)(solid_js.Show, {
@@ -5102,9 +5122,9 @@ function LimitsSection() {
5102
5122
  return message();
5103
5123
  },
5104
5124
  get children() {
5105
- var _el$3 = _tmpl$3$20();
5106
- (0, solid_js_web.insert)(_el$3, message);
5107
- return _el$3;
5125
+ var _el$2 = _tmpl$2$37();
5126
+ (0, solid_js_web.insert)(_el$2, message);
5127
+ return _el$2;
5108
5128
  }
5109
5129
  }),
5110
5130
  (0, solid_js_web.createComponent)(solid_js.Show, {
@@ -5121,13 +5141,13 @@ function LimitsSection() {
5121
5141
  return value().balances;
5122
5142
  },
5123
5143
  children: (balance) => (() => {
5124
- var _el$4 = _tmpl$4$12(), _el$5 = _el$4.firstChild;
5125
- (0, solid_js_web.insert)(_el$4, () => balance.label, _el$5);
5126
- (0, solid_js_web.insert)(_el$4, (() => {
5144
+ var _el$3 = _tmpl$3$23(), _el$4 = _el$3.firstChild;
5145
+ (0, solid_js_web.insert)(_el$3, () => balance.label, _el$4);
5146
+ (0, solid_js_web.insert)(_el$3, (() => {
5127
5147
  var _c$ = (0, solid_js_web.memo)(() => !!balance.unlimited);
5128
5148
  return () => _c$() ? "Unlimited" : `${balance.amount} ${balance.unit ?? ""}`;
5129
5149
  })(), null);
5130
- return _el$4;
5150
+ return _el$3;
5131
5151
  })()
5132
5152
  })]
5133
5153
  })
@@ -5590,23 +5610,34 @@ function createMcpModel(options, persist, preferences) {
5590
5610
  };
5591
5611
  }
5592
5612
  // src/pages/navigator/ui/gui/mcp-indicator.tsx
5593
- var _tmpl$$48 = /*#__PURE__*/ (0, solid_js_web.template)(`<span style="display:inline-flex;width:12px;height:12px;flex-shrink:0;border-radius:50%;border:1px solid currentColor">`);
5613
+ var _tmpl$$53 = /*#__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">`);
5614
+ var _tmpl$2$36 = /*#__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>`);
5594
5615
  function McpIndicator(props) {
5616
+ const Loader = useNavigatorGui().ui.Loader;
5595
5617
  return (() => {
5596
- var _el$ = _tmpl$$48();
5597
- (0, solid_js_web.effect)((_p$) => {
5598
- var _v$ = props.status, _v$2 = props.status === "pending" ? "dotted" : "solid", _v$3 = props.status === "connected" ? "currentColor" : "transparent", _v$4 = props.status === "failed" ? 1 : .65;
5599
- _v$ !== _p$.e && (0, solid_js_web.setAttribute)(_el$, "aria-label", _p$.e = _v$);
5600
- _v$2 !== _p$.t && (0, solid_js_web.setStyleProperty)(_el$, "border-style", _p$.t = _v$2);
5601
- _v$3 !== _p$.a && (0, solid_js_web.setStyleProperty)(_el$, "background", _p$.a = _v$3);
5602
- _v$4 !== _p$.o && (0, solid_js_web.setStyleProperty)(_el$, "opacity", _p$.o = _v$4);
5603
- return _p$;
5604
- }, {
5605
- e: void 0,
5606
- t: void 0,
5607
- a: void 0,
5608
- o: void 0
5609
- });
5618
+ var _el$ = _tmpl$2$36();
5619
+ (0, solid_js_web.insert)(_el$, (0, solid_js_web.createComponent)(solid_js.Show, {
5620
+ get when() {
5621
+ return props.status !== "pending";
5622
+ },
5623
+ get fallback() {
5624
+ return (0, solid_js_web.createComponent)(Loader, { size: "small" });
5625
+ },
5626
+ get children() {
5627
+ var _el$2 = _tmpl$$53();
5628
+ (0, solid_js_web.effect)((_p$) => {
5629
+ var _v$ = props.status === "connected" ? "currentColor" : "transparent", _v$2 = props.status === "failed" ? 1 : .65;
5630
+ _v$ !== _p$.e && (0, solid_js_web.setStyleProperty)(_el$2, "background", _p$.e = _v$);
5631
+ _v$2 !== _p$.t && (0, solid_js_web.setStyleProperty)(_el$2, "opacity", _p$.t = _v$2);
5632
+ return _p$;
5633
+ }, {
5634
+ e: void 0,
5635
+ t: void 0
5636
+ });
5637
+ return _el$2;
5638
+ }
5639
+ }));
5640
+ (0, solid_js_web.effect)(() => (0, solid_js_web.setAttribute)(_el$, "aria-label", props.status));
5610
5641
  return _el$;
5611
5642
  })();
5612
5643
  }
@@ -5661,22 +5692,44 @@ function GuiMcpRow(props) {
5661
5692
  });
5662
5693
  }
5663
5694
  // src/pages/navigator/ui/gui/mcp-group.tsx
5664
- var _tmpl$$47 = /*#__PURE__*/ (0, solid_js_web.template)(`<div><button type=button style="display:flex;gap:6px;align-items:center;width:100%;padding:4px 0;border:0;background:transparent;color:inherit;text-align:left"><strong style=overflow:hidden;text-overflow:ellipsis;white-space:nowrap></strong><span style=opacity:0.6;font-weight:400></span></button><ul style="margin:0;padding:0 0 0 10px;list-style:none">`);
5695
+ var _tmpl$$52 = /*#__PURE__*/ (0, solid_js_web.template)(`<strong style=overflow:hidden;text-overflow:ellipsis;white-space:nowrap>`);
5696
+ var _tmpl$2$35 = /*#__PURE__*/ (0, solid_js_web.template)(`<span style=opacity:0.6;font-weight:400>`);
5697
+ var _tmpl$3$22 = /*#__PURE__*/ (0, solid_js_web.template)(`<div><ul style="margin:0;padding:0 0 0 10px;list-style:none">`);
5665
5698
  function GuiMcpGroup(props) {
5666
5699
  const services = useNavigatorGui();
5667
5700
  const catalogs = () => services.runtime.catalogs;
5668
5701
  const view = () => catalogs().views.mcp;
5669
5702
  const bucket = () => view().bucket(props.group);
5670
5703
  const busy = () => catalogs().mcp.bulkState().group === props.group && catalogs().mcp.bulkState().status === "running";
5704
+ const Button = services.ui.Button;
5671
5705
  return (() => {
5672
- var _el$ = _tmpl$$47(), _el$2 = _el$.firstChild, _el$3 = _el$2.firstChild, _el$4 = _el$3.nextSibling, _el$5 = _el$2.nextSibling;
5673
- _el$2.$$click = () => void catalogs().mcp.toggleGroup(props.group, bucket().map((item) => item.name))?.catch(() => {});
5674
- (0, solid_js_web.insert)(_el$2, (0, solid_js_web.createComponent)(McpIndicator, { get status() {
5675
- return mcpGroupStatus(bucket(), busy());
5676
- } }), _el$3);
5677
- (0, solid_js_web.insert)(_el$3, () => props.group);
5678
- (0, solid_js_web.insert)(_el$4, () => bucket().length);
5679
- (0, solid_js_web.insert)(_el$5, (0, solid_js_web.createComponent)(solid_js.For, {
5706
+ var _el$ = _tmpl$3$22(), _el$4 = _el$.firstChild;
5707
+ (0, solid_js_web.insert)(_el$, (0, solid_js_web.createComponent)(Button, {
5708
+ variant: "ghost",
5709
+ size: "small",
5710
+ get disabled() {
5711
+ return catalogs().mcp.mutating();
5712
+ },
5713
+ onClick: () => void catalogs().mcp.toggleGroup(props.group, bucket().map((item) => item.name))?.catch(() => {}),
5714
+ get children() {
5715
+ return [
5716
+ (0, solid_js_web.createComponent)(McpIndicator, { get status() {
5717
+ return mcpGroupStatus(bucket(), busy());
5718
+ } }),
5719
+ (() => {
5720
+ var _el$2 = _tmpl$$52();
5721
+ (0, solid_js_web.insert)(_el$2, () => props.group);
5722
+ return _el$2;
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, {
5680
5733
  get each() {
5681
5734
  return view().visibility.visible().filter((item) => item.bucket === props.group).map((item) => item.name);
5682
5735
  },
@@ -5689,16 +5742,14 @@ function GuiMcpGroup(props) {
5689
5742
  } })
5690
5743
  })
5691
5744
  }));
5692
- (0, solid_js_web.effect)(() => _el$2.disabled = catalogs().mcp.mutating());
5693
5745
  return _el$;
5694
5746
  })();
5695
5747
  }
5696
- (0, solid_js_web.delegateEvents)(["click"]);
5697
5748
  // src/pages/navigator/ui/gui/mcp-section.tsx
5698
- var _tmpl$$46 = /*#__PURE__*/ (0, solid_js_web.template)(`<p role=alert>`);
5699
- var _tmpl$2$32 = /*#__PURE__*/ (0, solid_js_web.template)(`<p role=status>/<!> servers updated`);
5700
- var _tmpl$3$19 = /*#__PURE__*/ (0, solid_js_web.template)(`<div style=display:flex;flex-direction:column;gap:12px>`);
5701
- var _tmpl$4$11 = /*#__PURE__*/ (0, solid_js_web.template)(`<p style=opacity:0.65>No matching MCP servers.`);
5749
+ var _tmpl$$51 = /*#__PURE__*/ (0, solid_js_web.template)(`<p role=alert>`);
5750
+ var _tmpl$2$34 = /*#__PURE__*/ (0, solid_js_web.template)(`<p role=status>/<!> servers updated`);
5751
+ var _tmpl$3$21 = /*#__PURE__*/ (0, solid_js_web.template)(`<div style=display:flex;flex-direction:column;gap:12px>`);
5752
+ var _tmpl$4$12 = /*#__PURE__*/ (0, solid_js_web.template)(`<p style=opacity:0.65>No matching MCP servers.`);
5702
5753
  function McpSection() {
5703
5754
  const services = useNavigatorGui();
5704
5755
  const catalogs = () => services.runtime.catalogs;
@@ -5750,7 +5801,7 @@ function McpSection() {
5750
5801
  },
5751
5802
  get children() {
5752
5803
  return [(() => {
5753
- var _el$ = _tmpl$$46();
5804
+ var _el$ = _tmpl$$51();
5754
5805
  (0, solid_js_web.insert)(_el$, () => state().error?.message);
5755
5806
  return _el$;
5756
5807
  })(), (0, solid_js_web.createComponent)(Button, {
@@ -5766,7 +5817,7 @@ function McpSection() {
5766
5817
  },
5767
5818
  get children() {
5768
5819
  return [(() => {
5769
- var _el$2 = _tmpl$2$32(), _el$3 = _el$2.firstChild, _el$5 = _el$3.nextSibling;
5820
+ var _el$2 = _tmpl$2$34(), _el$3 = _el$2.firstChild, _el$5 = _el$3.nextSibling;
5770
5821
  _el$5.nextSibling;
5771
5822
  (0, solid_js_web.insert)(_el$2, () => bulk().completed, _el$3);
5772
5823
  (0, solid_js_web.insert)(_el$2, () => bulk().total, _el$5);
@@ -5786,13 +5837,13 @@ function McpSection() {
5786
5837
  }
5787
5838
  }),
5788
5839
  (() => {
5789
- var _el$6 = _tmpl$3$19();
5840
+ var _el$6 = _tmpl$3$21();
5790
5841
  (0, solid_js_web.insert)(_el$6, (0, solid_js_web.createComponent)(solid_js.For, {
5791
5842
  get each() {
5792
5843
  return view().groups();
5793
5844
  },
5794
5845
  get fallback() {
5795
- return _tmpl$4$11();
5846
+ return _tmpl$4$12();
5796
5847
  },
5797
5848
  children: (group) => (0, solid_js_web.createComponent)(GuiMcpGroup, { group })
5798
5849
  }));
@@ -5861,10 +5912,10 @@ function GuiSkillRow(props) {
5861
5912
  });
5862
5913
  }
5863
5914
  // src/pages/navigator/ui/gui/skills-section.tsx
5864
- var _tmpl$$45 = /*#__PURE__*/ (0, solid_js_web.template)(`<p role=alert>`);
5865
- var _tmpl$2$31 = /*#__PURE__*/ (0, solid_js_web.template)(`<div style=display:flex;flex-direction:column;gap:12px>`);
5866
- var _tmpl$3$18 = /*#__PURE__*/ (0, solid_js_web.template)(`<p style=opacity:0.65>No matching Skills.`);
5867
- var _tmpl$4$10 = /*#__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">`);
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">`);
5868
5919
  function SkillsSection() {
5869
5920
  const services = useNavigatorGui();
5870
5921
  const catalogs = () => services.runtime.catalogs;
@@ -5894,7 +5945,7 @@ function SkillsSection() {
5894
5945
  },
5895
5946
  get children() {
5896
5947
  return [(() => {
5897
- var _el$ = _tmpl$$45();
5948
+ var _el$ = _tmpl$$50();
5898
5949
  (0, solid_js_web.insert)(_el$, () => catalogs().skills.error());
5899
5950
  return _el$;
5900
5951
  })(), (0, solid_js_web.createComponent)(Button, {
@@ -5905,16 +5956,16 @@ function SkillsSection() {
5905
5956
  }
5906
5957
  }),
5907
5958
  (() => {
5908
- var _el$2 = _tmpl$2$31();
5959
+ var _el$2 = _tmpl$2$33();
5909
5960
  (0, solid_js_web.insert)(_el$2, (0, solid_js_web.createComponent)(solid_js.For, {
5910
5961
  get each() {
5911
5962
  return view().groups();
5912
5963
  },
5913
5964
  get fallback() {
5914
- return _tmpl$3$18();
5965
+ return _tmpl$3$20();
5915
5966
  },
5916
5967
  children: (group) => (() => {
5917
- var _el$4 = _tmpl$4$10(), _el$5 = _el$4.firstChild, _el$6 = _el$5.nextSibling;
5968
+ var _el$4 = _tmpl$4$11(), _el$5 = _el$4.firstChild, _el$6 = _el$5.nextSibling;
5918
5969
  (0, solid_js_web.insert)(_el$5, group);
5919
5970
  (0, solid_js_web.insert)(_el$6, (0, solid_js_web.createComponent)(solid_js.For, {
5920
5971
  get each() {
@@ -6369,9 +6420,9 @@ function createSubagentClock(key) {
6369
6420
  return now;
6370
6421
  }
6371
6422
  // src/shared/ui/gui/tabs.tsx
6372
- var _tmpl$$44 = /*#__PURE__*/ (0, solid_js_web.template)(`<nav style=display:flex;gap:4px;flex-wrap:wrap>`);
6373
- var _tmpl$2$30 = /*#__PURE__*/ (0, solid_js_web.template)(`<span>`);
6374
- var _tmpl$3$17 = /*#__PURE__*/ (0, solid_js_web.template)(`<span style=opacity:0.6;font-weight:400>`);
6423
+ var _tmpl$$49 = /*#__PURE__*/ (0, solid_js_web.template)(`<nav style=display:flex;gap:4px;flex-wrap:wrap>`);
6424
+ var _tmpl$2$32 = /*#__PURE__*/ (0, solid_js_web.template)(`<span>`);
6425
+ var _tmpl$3$19 = /*#__PURE__*/ (0, solid_js_web.template)(`<span style=opacity:0.6;font-weight:400>`);
6375
6426
  function GuiTabs(props) {
6376
6427
  const Button = props.ui.Button;
6377
6428
  function navigate(event) {
@@ -6385,7 +6436,7 @@ function GuiTabs(props) {
6385
6436
  event.currentTarget.querySelectorAll("button:not(:disabled)")[next]?.focus();
6386
6437
  }
6387
6438
  return (() => {
6388
- var _el$ = _tmpl$$44();
6439
+ var _el$ = _tmpl$$49();
6389
6440
  _el$.$$keydown = navigate;
6390
6441
  (0, solid_js_web.insert)(_el$, (0, solid_js_web.createComponent)(solid_js.For, {
6391
6442
  get each() {
@@ -6404,7 +6455,7 @@ function GuiTabs(props) {
6404
6455
  onClick: () => props.onSelect(id),
6405
6456
  get children() {
6406
6457
  return [(() => {
6407
- var _el$2 = _tmpl$2$30();
6458
+ var _el$2 = _tmpl$2$32();
6408
6459
  (0, solid_js_web.insert)(_el$2, () => option().label);
6409
6460
  (0, solid_js_web.effect)((_$p) => (0, solid_js_web.setStyleProperty)(_el$2, "font-weight", props.selected === id ? "600" : "400"));
6410
6461
  return _el$2;
@@ -6413,7 +6464,7 @@ function GuiTabs(props) {
6413
6464
  return option().count !== void 0;
6414
6465
  },
6415
6466
  get children() {
6416
- var _el$3 = _tmpl$3$17();
6467
+ var _el$3 = _tmpl$3$19();
6417
6468
  (0, solid_js_web.insert)(_el$3, () => option().count);
6418
6469
  return _el$3;
6419
6470
  }
@@ -6478,9 +6529,9 @@ function iconChoiceLabel(id) {
6478
6529
  return id.replaceAll("-", " ");
6479
6530
  }
6480
6531
  // src/shared/ui/gui/icon.tsx
6481
- var _tmpl$$43 = /*#__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>`);
6482
- var _tmpl$2$29 = /*#__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>`);
6483
- var _tmpl$3$16 = /*#__PURE__*/ (0, solid_js_web.template)(`<svg><path></svg>`, false, true, false);
6532
+ var _tmpl$$48 = /*#__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>`);
6533
+ var _tmpl$2$31 = /*#__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>`);
6534
+ var _tmpl$3$18 = /*#__PURE__*/ (0, solid_js_web.template)(`<svg><path></svg>`, false, true, false);
6484
6535
  var native = {
6485
6536
  plus: "plus",
6486
6537
  check: "check",
@@ -6546,20 +6597,20 @@ function GuiIcon(props) {
6546
6597
  const Icon = props.ui.Icon;
6547
6598
  const id = () => isIconChoiceId(props.id) ? props.id : "bolt";
6548
6599
  return (() => {
6549
- var _el$ = _tmpl$$43();
6600
+ var _el$ = _tmpl$$48();
6550
6601
  (0, solid_js_web.insert)(_el$, (0, solid_js_web.createComponent)(solid_js.Show, {
6551
6602
  get when() {
6552
6603
  return native[id()];
6553
6604
  },
6554
6605
  get fallback() {
6555
6606
  return (() => {
6556
- var _el$2 = _tmpl$2$29();
6607
+ var _el$2 = _tmpl$2$31();
6557
6608
  (0, solid_js_web.insert)(_el$2, (0, solid_js_web.createComponent)(solid_js.For, {
6558
6609
  get each() {
6559
6610
  return paths[id()] ?? paths.bolt;
6560
6611
  },
6561
6612
  children: (path) => (() => {
6562
- var _el$3 = _tmpl$3$16();
6613
+ var _el$3 = _tmpl$3$18();
6563
6614
  (0, solid_js_web.setAttribute)(_el$3, "d", path);
6564
6615
  return _el$3;
6565
6616
  })()
@@ -6578,12 +6629,12 @@ function GuiIcon(props) {
6578
6629
  })();
6579
6630
  }
6580
6631
  // src/shared/ui/gui/multiline-field.tsx
6581
- var _tmpl$$42 = /*#__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">`);
6632
+ var _tmpl$$47 = /*#__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">`);
6582
6633
  function GuiMultilineField(props) {
6583
6634
  const id = (0, solid_js.createUniqueId)();
6584
6635
  const [focused, setFocused] = (0, solid_js.createSignal)(false);
6585
6636
  return (() => {
6586
- var _el$ = _tmpl$$42(), _el$2 = _el$.firstChild, _el$3 = _el$2.nextSibling;
6637
+ var _el$ = _tmpl$$47(), _el$2 = _el$.firstChild, _el$3 = _el$2.nextSibling;
6587
6638
  (0, solid_js_web.setAttribute)(_el$, "for", id);
6588
6639
  (0, solid_js_web.insert)(_el$2, () => props.label);
6589
6640
  _el$3.$$input = (event) => props.onInput(event.currentTarget.value);
@@ -6609,15 +6660,16 @@ function GuiMultilineField(props) {
6609
6660
  }
6610
6661
  (0, solid_js_web.delegateEvents)(["input"]);
6611
6662
  // src/shared/ui/gui/group-control.tsx
6612
- var _tmpl$$41 = /*#__PURE__*/ (0, solid_js_web.template)(`<div role=group style=display:flex;gap:8px;flex-wrap:wrap>`);
6663
+ var _tmpl$$46 = /*#__PURE__*/ (0, solid_js_web.template)(`<div role=group style=display:flex;gap:8px;flex-wrap:wrap>`);
6613
6664
  function GuiGroupControl(props) {
6614
6665
  const Select = props.ui.Select;
6615
6666
  const TextInput = props.ui.TextInput;
6616
6667
  const Button = props.ui.Button;
6617
6668
  const [draft, setDraft] = (0, solid_js.createSignal)("");
6669
+ const [creating, setCreating] = (0, solid_js.createSignal)(false);
6618
6670
  (0, solid_js.createEffect)(() => setDraft(props.value ?? ""));
6619
6671
  return (() => {
6620
- var _el$ = _tmpl$$41();
6672
+ var _el$ = _tmpl$$46();
6621
6673
  (0, solid_js_web.insert)(_el$, (0, solid_js_web.createComponent)(Select, {
6622
6674
  get label() {
6623
6675
  return `${props.label} existing group`;
@@ -6634,45 +6686,352 @@ function GuiGroupControl(props) {
6634
6686
  label: value
6635
6687
  }))];
6636
6688
  },
6637
- onChange: setDraft,
6689
+ onChange: (value) => {
6690
+ setDraft(value);
6691
+ setCreating(false);
6692
+ },
6638
6693
  get disabled() {
6639
6694
  return props.disabled;
6640
6695
  }
6641
6696
  }), null);
6642
- (0, solid_js_web.insert)(_el$, (0, solid_js_web.createComponent)(TextInput, {
6643
- get label() {
6644
- return `${props.label} new group`;
6645
- },
6646
- get value() {
6647
- return draft();
6648
- },
6649
- onInput: setDraft,
6697
+ (0, solid_js_web.insert)(_el$, (0, solid_js_web.createComponent)(Button, {
6698
+ size: "small",
6699
+ variant: "ghost",
6650
6700
  get disabled() {
6651
6701
  return props.disabled;
6652
6702
  },
6653
- get invalid() {
6654
- return draft().length > 64;
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
+ }
6728
+ });
6655
6729
  }
6656
6730
  }), null);
6657
- (0, solid_js_web.insert)(_el$, (0, solid_js_web.createComponent)(Button, {
6658
- size: "small",
6659
- get disabled() {
6660
- return props.disabled || draft().length > 64;
6731
+ (0, solid_js_web.insert)(_el$, (0, solid_js_web.createComponent)(solid_js.Show, {
6732
+ get when() {
6733
+ return creating() || draft() !== (props.value ?? "");
6661
6734
  },
6662
- onClick: () => props.save(draft().trim() || void 0),
6663
- children: "Save group"
6735
+ get children() {
6736
+ return [(0, solid_js_web.createComponent)(Button, {
6737
+ size: "small",
6738
+ get disabled() {
6739
+ return props.disabled || draft().length > 64 || creating() && !draft().trim();
6740
+ },
6741
+ onClick: () => {
6742
+ props.save(draft().trim() || void 0);
6743
+ setCreating(false);
6744
+ },
6745
+ children: "Save group"
6746
+ }), (0, solid_js_web.createComponent)(Button, {
6747
+ size: "small",
6748
+ variant: "ghost",
6749
+ onClick: () => {
6750
+ setDraft(props.value ?? "");
6751
+ setCreating(false);
6752
+ },
6753
+ children: "Cancel"
6754
+ })];
6755
+ }
6664
6756
  }), null);
6665
6757
  (0, solid_js_web.effect)(() => (0, solid_js_web.setAttribute)(_el$, "aria-label", `${props.label} grouping`));
6666
6758
  return _el$;
6667
6759
  })();
6668
6760
  }
6761
+ // src/shared/ui/gui/settings-surface.tsx
6762
+ var _tmpl$$45 = /*#__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`);
6763
+ function GuiSettingsSurface(props) {
6764
+ return (() => {
6765
+ var _el$ = _tmpl$$45();
6766
+ _el$.firstChild;
6767
+ (0, solid_js_web.insert)(_el$, () => props.children, null);
6768
+ return _el$;
6769
+ })();
6770
+ }
6771
+ // src/shared/ui/gui/sortable-focus.ts
6772
+ function createSortableFocus(props) {
6773
+ let focused;
6774
+ (0, solid_js.createEffect)(() => {
6775
+ const keys = props.keys();
6776
+ const disabled = props.disabled();
6777
+ const key = focused;
6778
+ if (!key || disabled || !keys.includes(key)) return;
6779
+ queueMicrotask(() => {
6780
+ if (focused !== key || props.disabled() || document.activeElement !== document.body) return;
6781
+ [...props.root().querySelectorAll("[data-sortable-item]")].find((node) => node.dataset.sortableItem === key)?.querySelector("button")?.focus({ preventScroll: true });
6782
+ });
6783
+ });
6784
+ return {
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();
6817
+ }
6818
+ (0, solid_js.createEffect)(() => {
6819
+ if (!source()) return;
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);
6828
+ }
6829
+ function start(event, id) {
6830
+ if (event.button !== 0 || props.disabled() || drag) return;
6831
+ event.preventDefault();
6832
+ event.stopPropagation();
6833
+ drag = {
6834
+ id,
6835
+ pointer: event.pointerId,
6836
+ scope: props.scope(),
6837
+ keys: signature()
6838
+ };
6839
+ props.root().setPointerCapture(event.pointerId);
6840
+ setSource(id);
6841
+ setTarget(id);
6842
+ }
6843
+ function end(event) {
6844
+ if (!drag || event.pointerId !== drag.pointer) return;
6845
+ hover(event);
6846
+ const current = drag;
6847
+ const destination = target();
6848
+ const valid = !props.disabled() && props.scope() === current.scope && signature() === current.keys;
6849
+ cancel();
6850
+ if (valid && destination && current.id !== destination) props.move(current.id, destination);
6851
+ }
6852
+ function key(event, id) {
6853
+ if (event.key === "Escape") {
6854
+ if (drag) {
6855
+ event.preventDefault();
6856
+ event.stopPropagation();
6857
+ cancel();
6858
+ }
6859
+ return;
6860
+ }
6861
+ if (props.disabled()) return;
6862
+ if ([" ", "Enter"].includes(event.key) && !event.repeat) {
6863
+ event.preventDefault();
6864
+ event.stopPropagation();
6865
+ if (!drag) {
6866
+ drag = {
6867
+ id,
6868
+ pointer: -1,
6869
+ scope: props.scope(),
6870
+ keys: signature()
6871
+ };
6872
+ setSource(id);
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);
6880
+ }
6881
+ return;
6882
+ }
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
+ };
6903
+ }
6904
+ // src/shared/ui/gui/sortable-list.tsx
6905
+ var _tmpl$$44 = /*#__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. `);
6906
+ var _tmpl$2$30 = /*#__PURE__*/ (0, solid_js_web.template)(`<div role=listitem>`);
6907
+ var _tmpl$3$17 = /*#__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>`);
6908
+ function GuiSortableList(props) {
6909
+ let root;
6910
+ const help = (0, solid_js.createUniqueId)();
6911
+ const IconButton = props.ui.IconButton;
6912
+ const keys = () => props.items.map((item) => props.itemKey(item));
6913
+ const focus = createSortableFocus({
6914
+ root: () => root,
6915
+ keys,
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)
6924
+ });
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
+ }
6985
+ (0, solid_js_web.delegateEvents)([
6986
+ "focusin",
6987
+ "focusout",
6988
+ "pointermove",
6989
+ "pointerup",
6990
+ "pointerdown",
6991
+ "keydown"
6992
+ ]);
6993
+ // src/shared/ui/gui/progress.tsx
6994
+ var _tmpl$$43 = /*#__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)>`);
6995
+ function GuiProgress(props) {
6996
+ const Loader = props.ui.Loader;
6997
+ return (() => {
6998
+ var _el$ = _tmpl$$43(), _el$3 = _el$.firstChild.nextSibling, _el$5 = _el$3.nextSibling.firstChild;
6999
+ (0, solid_js_web.insert)(_el$3, (0, solid_js_web.createComponent)(solid_js.Show, {
7000
+ get when() {
7001
+ return props.value === void 0;
7002
+ },
7003
+ get children() {
7004
+ return (0, solid_js_web.createComponent)(Loader, { size: "small" });
7005
+ }
7006
+ }), null);
7007
+ (0, solid_js_web.insert)(_el$3, () => props.label, null);
7008
+ (0, solid_js_web.effect)((_p$) => {
7009
+ 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;
7010
+ _v$ !== _p$.e && (0, solid_js_web.setAttribute)(_el$, "aria-label", _p$.e = _v$);
7011
+ _v$2 !== _p$.t && (0, solid_js_web.setAttribute)(_el$, "aria-valuenow", _p$.t = _v$2);
7012
+ _v$3 !== _p$.a && (0, solid_js_web.setAttribute)(_el$, "aria-valuetext", _p$.a = _v$3);
7013
+ _v$4 !== _p$.o && (0, solid_js_web.setAttribute)(_el$5, "data-navigator-install-pulse", _p$.o = _v$4);
7014
+ _v$5 !== _p$.i && (0, solid_js_web.setStyleProperty)(_el$5, "width", _p$.i = _v$5);
7015
+ _v$6 !== _p$.n && (0, solid_js_web.setStyleProperty)(_el$5, "animation", _p$.n = _v$6);
7016
+ return _p$;
7017
+ }, {
7018
+ e: void 0,
7019
+ t: void 0,
7020
+ a: void 0,
7021
+ o: void 0,
7022
+ i: void 0,
7023
+ n: void 0
7024
+ });
7025
+ return _el$;
7026
+ })();
7027
+ }
6669
7028
  // src/pages/navigator/ui/gui/subagent-row.tsx
6670
- var _tmpl$$40 = /*#__PURE__*/ (0, solid_js_web.template)(`<li><p style="font-size:12px;opacity:0.65;margin:0 0 8px;overflow-wrap:anywhere">`);
6671
- var _tmpl$2$28 = /*#__PURE__*/ (0, solid_js_web.template)(`<span> · `);
7029
+ 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">`);
7030
+ var _tmpl$2$29 = /*#__PURE__*/ (0, solid_js_web.template)(`<span> · `);
6672
7031
  function SubagentRow(props) {
6673
7032
  const Button = props.ui.Button;
6674
7033
  return (() => {
6675
- var _el$ = _tmpl$$40(), _el$2 = _el$.firstChild;
7034
+ var _el$ = _tmpl$$42(), _el$2 = _el$.firstChild;
6676
7035
  (0, solid_js_web.insert)(_el$, (0, solid_js_web.createComponent)(Button, {
6677
7036
  size: "small",
6678
7037
  variant: "ghost",
@@ -6689,7 +7048,7 @@ function SubagentRow(props) {
6689
7048
  return props.item.run;
6690
7049
  },
6691
7050
  children: (run) => (() => {
6692
- var _el$3 = _tmpl$2$28();
7051
+ var _el$3 = _tmpl$2$29();
6693
7052
  _el$3.firstChild;
6694
7053
  (0, solid_js_web.insert)(_el$3, () => run().startedBeforeObservation ? "Observed after start · " : "", null);
6695
7054
  (0, solid_js_web.insert)(_el$3, () => formatSubagentDuration(run().startedAt, run().finishedAt ?? props.now), null);
@@ -6700,9 +7059,9 @@ function SubagentRow(props) {
6700
7059
  })();
6701
7060
  }
6702
7061
  // src/pages/navigator/ui/gui/subagent-section.tsx
6703
- var _tmpl$$39 = /*#__PURE__*/ (0, solid_js_web.template)(`<p role=alert>`);
6704
- var _tmpl$2$27 = /*#__PURE__*/ (0, solid_js_web.template)(`<ul style="padding:0;margin:8px 0 0;list-style:none">`);
6705
- var _tmpl$3$15 = /*#__PURE__*/ (0, solid_js_web.template)(`<p style=opacity:0.65>No matching subagents.`);
7062
+ var _tmpl$$41 = /*#__PURE__*/ (0, solid_js_web.template)(`<p role=alert>`);
7063
+ var _tmpl$2$28 = /*#__PURE__*/ (0, solid_js_web.template)(`<ul style="padding:0;margin:8px 0 0;list-style:none">`);
7064
+ var _tmpl$3$16 = /*#__PURE__*/ (0, solid_js_web.template)(`<p style=opacity:0.65>No matching subagents.`);
6706
7065
  function SubagentSection() {
6707
7066
  const props = useNavigatorGui();
6708
7067
  const mode = () => props.runtime.view.subagentMode();
@@ -6767,7 +7126,7 @@ function SubagentSection() {
6767
7126
  return state().error;
6768
7127
  },
6769
7128
  get children() {
6770
- var _el$ = _tmpl$$39();
7129
+ var _el$ = _tmpl$$41();
6771
7130
  (0, solid_js_web.insert)(_el$, () => state().error?.message);
6772
7131
  return _el$;
6773
7132
  }
@@ -6777,10 +7136,10 @@ function SubagentSection() {
6777
7136
  return rows().length > 0;
6778
7137
  },
6779
7138
  get fallback() {
6780
- return _tmpl$3$15();
7139
+ return _tmpl$3$16();
6781
7140
  },
6782
7141
  get children() {
6783
- var _el$2 = _tmpl$2$27();
7142
+ var _el$2 = _tmpl$2$28();
6784
7143
  (0, solid_js_web.insert)(_el$2, (0, solid_js_web.createComponent)(solid_js.For, {
6785
7144
  get each() {
6786
7145
  return keys();
@@ -6959,26 +7318,95 @@ function buildTodoView(todos, mode) {
6959
7318
  }
6960
7319
  };
6961
7320
  }
7321
+ // src/pages/navigator/ui/gui/todo-presentation.ts
7322
+ function todoPresentation(status) {
7323
+ const finished = status === "completed" || status === "cancelled";
7324
+ return {
7325
+ decoration: finished ? "line-through" : "none",
7326
+ text: finished ? "var(--v2-text-text-faint)" : status === "in_progress" ? "var(--v2-text-text-base)" : "var(--v2-text-text-muted)",
7327
+ icon: status === "in_progress" ? "var(--v2-state-fg-warning)" : status === "completed" ? "var(--v2-icon-icon-muted)" : "var(--v2-icon-icon-faint)"
7328
+ };
7329
+ }
7330
+ // src/pages/navigator/ui/gui/todo-status-icon.tsx
7331
+ var _tmpl$$40 = /*#__PURE__*/ (0, solid_js_web.template)(`<svg><path d="M8 4a4 4 0 0 0 0 8V4Z"fill=currentColor></svg>`, false, true, false);
7332
+ var _tmpl$2$27 = /*#__PURE__*/ (0, solid_js_web.template)(`<svg><path d="M5 8 7.5 11 11 5.5"stroke=currentColor stroke-linecap=round stroke-linejoin=round></svg>`, false, true, false);
7333
+ var _tmpl$3$15 = /*#__PURE__*/ (0, solid_js_web.template)(`<svg><path d="M3.5 12.5 12.5 3.5"stroke=currentColor></svg>`, false, true, false);
7334
+ var _tmpl$4$10 = /*#__PURE__*/ (0, solid_js_web.template)(`<span role=img style=display:inline-flex;height:20px;align-items:center;flex-shrink:0><svg width=16 height=16 viewBox="0 0 16 16"fill=none aria-hidden=true><circle cx=8 cy=8 r=6.5 stroke=currentColor>`);
7335
+ function TodoStatusIcon(props) {
7336
+ const color = () => todoPresentation(props.status).icon;
7337
+ return (() => {
7338
+ var _el$ = _tmpl$4$10(), _el$2 = _el$.firstChild;
7339
+ _el$2.firstChild;
7340
+ (0, solid_js_web.insert)(_el$2, (0, solid_js_web.createComponent)(solid_js.Switch, { get children() {
7341
+ return [
7342
+ (0, solid_js_web.createComponent)(solid_js.Match, {
7343
+ get when() {
7344
+ return props.status === "in_progress";
7345
+ },
7346
+ get children() {
7347
+ return _tmpl$$40();
7348
+ }
7349
+ }),
7350
+ (0, solid_js_web.createComponent)(solid_js.Match, {
7351
+ get when() {
7352
+ return props.status === "completed";
7353
+ },
7354
+ get children() {
7355
+ return _tmpl$2$27();
7356
+ }
7357
+ }),
7358
+ (0, solid_js_web.createComponent)(solid_js.Match, {
7359
+ get when() {
7360
+ return props.status === "cancelled";
7361
+ },
7362
+ get children() {
7363
+ return _tmpl$3$15();
7364
+ }
7365
+ })
7366
+ ];
7367
+ } }), null);
7368
+ (0, solid_js_web.effect)((_p$) => {
7369
+ var _v$ = props.status, _v$2 = color();
7370
+ _v$ !== _p$.e && (0, solid_js_web.setAttribute)(_el$, "aria-label", _p$.e = _v$);
7371
+ _v$2 !== _p$.t && (0, solid_js_web.setStyleProperty)(_el$, "color", _p$.t = _v$2);
7372
+ return _p$;
7373
+ }, {
7374
+ e: void 0,
7375
+ t: void 0
7376
+ });
7377
+ return _el$;
7378
+ })();
7379
+ }
6962
7380
  // src/pages/navigator/ui/gui/todo-row.tsx
6963
- var _tmpl$$38 = /*#__PURE__*/ (0, solid_js_web.template)(`<li style="padding:6px 0;overflow-wrap:anywhere"><span role=img style=opacity:0.6>`);
7381
+ var _tmpl$$39 = /*#__PURE__*/ (0, solid_js_web.template)(`<li data-navigator-todo-row style="display:flex;align-items:flex-start;gap:8px;padding:4px 6px;min-width:0"><span dir=auto data-navigator-todo-text style=flex:1;min-width:0;overflow-wrap:anywhere;font-size:13px;line-height:var(--line-height-base);letter-spacing:-0.04px>`);
6964
7382
  function TodoRow(props) {
7383
+ const appearance = () => todoPresentation(props.item.status);
6965
7384
  return (() => {
6966
- var _el$ = _tmpl$$38(), _el$2 = _el$.firstChild;
6967
- (0, solid_js_web.insert)(_el$2, (() => {
6968
- var _c$ = (0, solid_js_web.memo)(() => props.item.status === "completed");
6969
- return () => _c$() ? "✓ " : props.item.status === "in_progress" ? "◉ " : "○ ";
6970
- })());
6971
- (0, solid_js_web.insert)(_el$, () => props.item.content, null);
6972
- (0, solid_js_web.effect)(() => (0, solid_js_web.setAttribute)(_el$2, "aria-label", props.item.status));
7385
+ var _el$ = _tmpl$$39(), _el$2 = _el$.firstChild;
7386
+ (0, solid_js_web.insert)(_el$, (0, solid_js_web.createComponent)(TodoStatusIcon, { get status() {
7387
+ return props.item.status;
7388
+ } }), _el$2);
7389
+ (0, solid_js_web.insert)(_el$2, () => props.item.content);
7390
+ (0, solid_js_web.effect)((_p$) => {
7391
+ var _v$ = props.item.status, _v$2 = appearance().text, _v$3 = appearance().decoration;
7392
+ _v$ !== _p$.e && (0, solid_js_web.setAttribute)(_el$, "data-status", _p$.e = _v$);
7393
+ _v$2 !== _p$.t && (0, solid_js_web.setStyleProperty)(_el$2, "color", _p$.t = _v$2);
7394
+ _v$3 !== _p$.a && (0, solid_js_web.setStyleProperty)(_el$2, "text-decoration", _p$.a = _v$3);
7395
+ return _p$;
7396
+ }, {
7397
+ e: void 0,
7398
+ t: void 0,
7399
+ a: void 0
7400
+ });
6973
7401
  return _el$;
6974
7402
  })();
6975
7403
  }
6976
7404
  // src/pages/navigator/ui/gui/todo-section.tsx
6977
- var _tmpl$$37 = /*#__PURE__*/ (0, solid_js_web.template)(`<p role=alert>`);
7405
+ var _tmpl$$38 = /*#__PURE__*/ (0, solid_js_web.template)(`<p role=alert>`);
6978
7406
  var _tmpl$2$26 = /*#__PURE__*/ (0, solid_js_web.template)(`<p style=opacity:0.65;font-size:12px> completed of `);
6979
7407
  var _tmpl$3$14 = /*#__PURE__*/ (0, solid_js_web.template)(`<p role=status>Reading Todo configuration…`);
6980
7408
  var _tmpl$4$9 = /*#__PURE__*/ (0, solid_js_web.template)(`<div><p>`);
6981
- var _tmpl$5$5 = /*#__PURE__*/ (0, solid_js_web.template)(`<p style=opacity:0.65>No matching tasks. Manage Todo through chat.`);
7409
+ var _tmpl$5$4 = /*#__PURE__*/ (0, solid_js_web.template)(`<p style=opacity:0.65>No matching tasks. Manage Todo through chat.`);
6982
7410
  var _tmpl$6$2 = /*#__PURE__*/ (0, solid_js_web.template)(`<div><h3 style=font-size:12px;opacity:0.65></h3><ul style=padding:0;margin:0;list-style:none>`);
6983
7411
  function TodoSection() {
6984
7412
  const props = useNavigatorGui();
@@ -7076,7 +7504,7 @@ function TodoSection() {
7076
7504
  return state().error;
7077
7505
  },
7078
7506
  get children() {
7079
- var _el$ = _tmpl$$37();
7507
+ var _el$ = _tmpl$$38();
7080
7508
  (0, solid_js_web.insert)(_el$, () => state().error?.message);
7081
7509
  return _el$;
7082
7510
  }
@@ -7086,7 +7514,7 @@ function TodoSection() {
7086
7514
  return setup()?.status === "error";
7087
7515
  },
7088
7516
  get children() {
7089
- var _el$2 = _tmpl$$37();
7517
+ var _el$2 = _tmpl$$38();
7090
7518
  (0, solid_js_web.insert)(_el$2, () => setup()?.error);
7091
7519
  return _el$2;
7092
7520
  }
@@ -7096,7 +7524,7 @@ function TodoSection() {
7096
7524
  return view().rows.length > 0;
7097
7525
  },
7098
7526
  get fallback() {
7099
- return _tmpl$5$5();
7527
+ return _tmpl$5$4();
7100
7528
  },
7101
7529
  get children() {
7102
7530
  return [(() => {
@@ -7140,7 +7568,7 @@ function TodoSection() {
7140
7568
  });
7141
7569
  }
7142
7570
  // src/pages/navigator/ui/gui/sections.tsx
7143
- var _tmpl$$36 = /*#__PURE__*/ (0, solid_js_web.template)(`<hr style="border:0;border-top:1px solid currentColor;opacity:0.18;margin:14px 0">`);
7571
+ var _tmpl$$37 = /*#__PURE__*/ (0, solid_js_web.template)(`<hr style="border:0;border-top:1px solid currentColor;opacity:0.18;margin:14px 0">`);
7144
7572
  function NavigatorSections() {
7145
7573
  const services = useNavigatorGui();
7146
7574
  const preferences = () => services.runtime.catalogs?.preferences;
@@ -7159,7 +7587,7 @@ function NavigatorSections() {
7159
7587
  return index() > 0;
7160
7588
  },
7161
7589
  get children() {
7162
- return _tmpl$$36();
7590
+ return _tmpl$$37();
7163
7591
  }
7164
7592
  }), (0, solid_js_web.createComponent)(solid_js.Switch, { get children() {
7165
7593
  return [
@@ -7204,7 +7632,7 @@ function NavigatorSections() {
7204
7632
  });
7205
7633
  }
7206
7634
  // src/features/pinned-toolbar/ui/gui/icon-picker.tsx
7207
- var _tmpl$$35 = /*#__PURE__*/ (0, solid_js_web.template)(`<div style="display:grid;grid-template-columns:repeat(auto-fit, minmax(110px, 1fr));gap:4px;margin:8px 0">`);
7635
+ var _tmpl$$36 = /*#__PURE__*/ (0, solid_js_web.template)(`<div style="display:grid;grid-template-columns:repeat(auto-fit, minmax(110px, 1fr));gap:4px;margin:8px 0">`);
7208
7636
  function GuiIconPicker(props) {
7209
7637
  const Dialog = props.ui.Dialog;
7210
7638
  const Button = props.ui.Button;
@@ -7232,7 +7660,7 @@ function GuiIconPicker(props) {
7232
7660
  autofocus: true,
7233
7661
  "class": "w-full"
7234
7662
  }), (() => {
7235
- var _el$ = _tmpl$$35();
7663
+ var _el$ = _tmpl$$36();
7236
7664
  (0, solid_js_web.insert)(_el$, (0, solid_js_web.createComponent)(solid_js.For, {
7237
7665
  get each() {
7238
7666
  return choices();
@@ -7259,13 +7687,24 @@ function GuiIconPicker(props) {
7259
7687
  });
7260
7688
  }
7261
7689
  // src/features/pinned-toolbar/ui/gui/icon-group.tsx
7262
- var _tmpl$$34 = /*#__PURE__*/ (0, solid_js_web.template)(`<ol style=margin:0;padding:0;list-style:none>`);
7263
- var _tmpl$2$25 = /*#__PURE__*/ (0, solid_js_web.template)(`<li style="display:flex;gap:4px;margin:4px 0">`);
7690
+ var _tmpl$$35 = /*#__PURE__*/ (0, solid_js_web.template)(`<div style="display:flex;gap:4px;margin:4px 0">`);
7264
7691
  function GuiIconGroupEditor(props) {
7265
7692
  const Dialog = props.ui.Dialog;
7266
7693
  const Button = props.ui.Button;
7267
- const [values, setValues] = (0, solid_js.createSignal)([...props.initial]);
7268
- function choose(index) {
7694
+ let nextKey = props.initial.length;
7695
+ const [slots, setSlots] = (0, solid_js.createSignal)(props.initial.map((id, key) => ({
7696
+ id,
7697
+ key
7698
+ })));
7699
+ const values = () => slots().map((slot) => slot.id);
7700
+ function choose(key) {
7701
+ const select = (id) => setSlots((previous) => key === void 0 ? [...previous, {
7702
+ id,
7703
+ key: nextKey++
7704
+ }].slice(0, 3) : previous.map((slot) => slot.key === key ? {
7705
+ ...slot,
7706
+ id
7707
+ } : slot));
7269
7708
  props.dialogs.open((dialog) => (0, solid_js_web.createComponent)(GuiIconPicker, {
7270
7709
  get ui() {
7271
7710
  return props.ui;
@@ -7273,11 +7712,7 @@ function GuiIconGroupEditor(props) {
7273
7712
  get close() {
7274
7713
  return dialog.close;
7275
7714
  },
7276
- choose: (id) => setValues((previous) => {
7277
- const next = [...previous];
7278
- next[index] = id;
7279
- return next;
7280
- })
7715
+ choose: select
7281
7716
  }));
7282
7717
  }
7283
7718
  return (0, solid_js_web.createComponent)(Dialog, {
@@ -7299,59 +7734,64 @@ function GuiIconGroupEditor(props) {
7299
7734
  })];
7300
7735
  },
7301
7736
  get children() {
7302
- return [(() => {
7303
- var _el$ = _tmpl$$34();
7304
- (0, solid_js_web.insert)(_el$, (0, solid_js_web.createComponent)(solid_js.For, {
7305
- get each() {
7306
- return values().map((_value, index) => index);
7307
- },
7308
- children: (index) => (() => {
7309
- var _el$2 = _tmpl$2$25();
7310
- (0, solid_js_web.insert)(_el$2, (0, solid_js_web.createComponent)(Button, {
7311
- variant: "ghost",
7312
- onClick: () => choose(index),
7313
- get children() {
7314
- return [
7315
- (0, solid_js_web.createComponent)(GuiIcon, {
7316
- get ui() {
7317
- return props.ui;
7318
- },
7319
- get id() {
7320
- return values()[index];
7321
- }
7322
- }),
7323
- "Icon ",
7324
- index + 1,
7325
- ": ",
7326
- (0, solid_js_web.memo)(() => iconChoiceLabel(values()[index]))
7327
- ];
7328
- }
7329
- }), null);
7330
- (0, solid_js_web.insert)(_el$2, (0, solid_js_web.createComponent)(Button, {
7331
- variant: "ghost-muted",
7332
- onClick: () => setValues((previous) => previous.filter((_value, offset) => offset !== index)),
7333
- children: "Remove"
7334
- }), null);
7335
- return _el$2;
7336
- })()
7337
- }));
7338
- return _el$;
7339
- })(), (0, solid_js_web.createComponent)(Button, {
7737
+ return [(0, solid_js_web.createComponent)(GuiSortableList, {
7738
+ get ui() {
7739
+ return props.ui;
7740
+ },
7741
+ label: "Button icon order",
7742
+ get items() {
7743
+ return slots();
7744
+ },
7745
+ itemKey: (slot) => String(slot.key),
7746
+ itemLabel: (slot) => `Icon ${slots().findIndex((value) => value.key === slot.key) + 1}: ${iconChoiceLabel(slot.id)}`,
7747
+ scope: "icon-draft",
7748
+ move: (from, to) => setSlots((previous) => reorderItems(previous, from, to, (slot) => String(slot.key))),
7749
+ children: (slot, handle) => (() => {
7750
+ var _el$ = _tmpl$$35();
7751
+ (0, solid_js_web.insert)(_el$, handle, null);
7752
+ (0, solid_js_web.insert)(_el$, (0, solid_js_web.createComponent)(Button, {
7753
+ variant: "ghost",
7754
+ onClick: () => choose(slot().key),
7755
+ get children() {
7756
+ return [
7757
+ (0, solid_js_web.createComponent)(GuiIcon, {
7758
+ get ui() {
7759
+ return props.ui;
7760
+ },
7761
+ get id() {
7762
+ return slot().id;
7763
+ }
7764
+ }),
7765
+ "Icon ",
7766
+ (0, solid_js_web.memo)(() => slots().findIndex((value) => value.key === slot().key) + 1),
7767
+ ": ",
7768
+ (0, solid_js_web.memo)(() => iconChoiceLabel(slot().id))
7769
+ ];
7770
+ }
7771
+ }), null);
7772
+ (0, solid_js_web.insert)(_el$, (0, solid_js_web.createComponent)(Button, {
7773
+ variant: "ghost-muted",
7774
+ onClick: () => setSlots((previous) => previous.filter((value) => value.key !== slot().key)),
7775
+ children: "Remove"
7776
+ }), null);
7777
+ return _el$;
7778
+ })()
7779
+ }), (0, solid_js_web.createComponent)(Button, {
7340
7780
  get disabled() {
7341
7781
  return values().length >= 3;
7342
7782
  },
7343
- onClick: () => choose(values().length),
7783
+ onClick: () => choose(),
7344
7784
  children: "Add icon"
7345
7785
  })];
7346
7786
  }
7347
7787
  });
7348
7788
  }
7349
7789
  // src/features/pinned-toolbar/ui/gui/pin-editor.tsx
7350
- var _tmpl$$33 = /*#__PURE__*/ (0, solid_js_web.template)(`<p>Base appearance`);
7351
- var _tmpl$2$24 = /*#__PURE__*/ (0, solid_js_web.template)(`<div style=display:flex;gap:4px;align-items:center><span>`);
7790
+ var _tmpl$$34 = /*#__PURE__*/ (0, solid_js_web.template)(`<p>Base appearance`);
7791
+ var _tmpl$2$25 = /*#__PURE__*/ (0, solid_js_web.template)(`<div style=display:flex;gap:4px;align-items:center><span>`);
7352
7792
  var _tmpl$3$13 = /*#__PURE__*/ (0, solid_js_web.template)(`<p role=alert>Use a single line of up to 128 characters.`);
7353
7793
  var _tmpl$4$8 = /*#__PURE__*/ (0, solid_js_web.template)(`<p>Saved state icons are retained. Desktop uses the base icons unless the action exposes its state publicly.`);
7354
- var _tmpl$5$4 = /*#__PURE__*/ (0, solid_js_web.template)(`<p role=alert>`);
7794
+ var _tmpl$5$3 = /*#__PURE__*/ (0, solid_js_web.template)(`<p role=alert>`);
7355
7795
  function GuiPinEditor(props) {
7356
7796
  const initial = toolbarPinAppearance(props.pin);
7357
7797
  const [base, setBase] = (0, solid_js.createSignal)([...initial.base]);
@@ -7438,9 +7878,9 @@ function GuiPinEditor(props) {
7438
7878
  },
7439
7879
  get children() {
7440
7880
  return [
7441
- _tmpl$$33(),
7881
+ _tmpl$$34(),
7442
7882
  (() => {
7443
- var _el$2 = _tmpl$2$24(), _el$3 = _el$2.firstChild;
7883
+ var _el$2 = _tmpl$2$25(), _el$3 = _el$2.firstChild;
7444
7884
  (0, solid_js_web.insert)(_el$2, (0, solid_js_web.createComponent)(solid_js.For, {
7445
7885
  get each() {
7446
7886
  return base();
@@ -7507,7 +7947,7 @@ function GuiPinEditor(props) {
7507
7947
  return error();
7508
7948
  },
7509
7949
  get children() {
7510
- var _el$6 = _tmpl$5$4();
7950
+ var _el$6 = _tmpl$5$3();
7511
7951
  (0, solid_js_web.insert)(_el$6, error);
7512
7952
  return _el$6;
7513
7953
  }
@@ -7517,11 +7957,10 @@ function GuiPinEditor(props) {
7517
7957
  });
7518
7958
  }
7519
7959
  // src/features/pinned-toolbar/ui/gui/manager.tsx
7520
- var _tmpl$$32 = /*#__PURE__*/ (0, solid_js_web.template)(`<p role=alert>`);
7521
- var _tmpl$2$23 = /*#__PURE__*/ (0, solid_js_web.template)(`<ol style=padding:0;margin:0;list-style:none>`);
7522
- var _tmpl$3$12 = /*#__PURE__*/ (0, solid_js_web.template)(`<li>Pin a Skill or Quick Action from its row menu.`);
7523
- var _tmpl$4$7 = /*#__PURE__*/ (0, solid_js_web.template)(`<small style=display:block;opacity:0.6>`);
7524
- var _tmpl$5$3 = /*#__PURE__*/ (0, solid_js_web.template)(`<li style="padding:8px 0;display:flex;gap:4px;align-items:center;min-width:0"><span style=flex:1;min-width:0;overflow-wrap:anywhere><strong>`);
7960
+ var _tmpl$$33 = /*#__PURE__*/ (0, solid_js_web.template)(`<p role=alert>`);
7961
+ var _tmpl$2$24 = /*#__PURE__*/ (0, solid_js_web.template)(`<p>Pin a Skill or Quick Action from its row menu.`);
7962
+ var _tmpl$3$12 = /*#__PURE__*/ (0, solid_js_web.template)(`<small style=display:block;opacity:0.6>`);
7963
+ var _tmpl$4$7 = /*#__PURE__*/ (0, solid_js_web.template)(`<div style="padding:8px 0;display:flex;gap:4px;align-items:center;min-width:0"><span style=flex:1;min-width:0;overflow-wrap:anywhere><strong>`);
7525
7964
  var source = (pin) => pin.kind === "skill" ? pin.location : void 0;
7526
7965
  function GuiToolbarManager(props) {
7527
7966
  const Dialog = props.ui.Dialog;
@@ -7561,85 +8000,78 @@ function GuiToolbarManager(props) {
7561
8000
  });
7562
8001
  },
7563
8002
  get children() {
7564
- return [(0, solid_js_web.createComponent)(solid_js.Show, {
7565
- get when() {
7566
- return error();
7567
- },
7568
- get children() {
7569
- var _el$ = _tmpl$$32();
7570
- (0, solid_js_web.insert)(_el$, error);
7571
- return _el$;
7572
- }
7573
- }), (() => {
7574
- var _el$2 = _tmpl$2$23();
7575
- (0, solid_js_web.insert)(_el$2, (0, solid_js_web.createComponent)(solid_js.For, {
7576
- get each() {
7577
- return props.pins.map((pin) => toolbarPinKey(pin));
8003
+ return [
8004
+ (0, solid_js_web.createComponent)(solid_js.Show, {
8005
+ get when() {
8006
+ return error();
7578
8007
  },
7579
- get fallback() {
7580
- return _tmpl$3$12();
8008
+ get children() {
8009
+ var _el$ = _tmpl$$33();
8010
+ (0, solid_js_web.insert)(_el$, error);
8011
+ return _el$;
8012
+ }
8013
+ }),
8014
+ (0, solid_js_web.createComponent)(solid_js.Show, {
8015
+ get when() {
8016
+ return props.pins.length === 0;
7581
8017
  },
7582
- children: (key, index) => (0, solid_js_web.createComponent)(solid_js.Show, {
7583
- get when() {
7584
- return props.pins.find((item) => toolbarPinKey(item) === key);
7585
- },
7586
- children: (pin) => (() => {
7587
- var _el$4 = _tmpl$5$3(), _el$5 = _el$4.firstChild, _el$6 = _el$5.firstChild;
7588
- (0, solid_js_web.insert)(_el$6, () => props.label(pin()));
7589
- (0, solid_js_web.insert)(_el$5, (0, solid_js_web.createComponent)(solid_js.Show, {
7590
- get when() {
7591
- return source(pin());
7592
- },
7593
- get children() {
7594
- var _el$7 = _tmpl$4$7();
7595
- (0, solid_js_web.insert)(_el$7, () => source(pin()));
7596
- return _el$7;
7597
- }
7598
- }), null);
7599
- (0, solid_js_web.insert)(_el$4, (0, solid_js_web.createComponent)(IconButton, {
7600
- icon: "arrow-up",
7601
- get label() {
7602
- return `Move ${props.label(pin())} up`;
7603
- },
7604
- get disabled() {
7605
- return busy() || index() === 0;
7606
- },
7607
- onClick: () => void run(() => props.move(key, -1))
7608
- }), null);
7609
- (0, solid_js_web.insert)(_el$4, (0, solid_js_web.createComponent)(IconButton, {
7610
- icon: "chevron-down",
7611
- get label() {
7612
- return `Move ${props.label(pin())} down`;
7613
- },
7614
- get disabled() {
7615
- return busy() || index() === props.pins.length - 1;
7616
- },
7617
- onClick: () => void run(() => props.move(key, 1))
7618
- }), null);
7619
- (0, solid_js_web.insert)(_el$4, (0, solid_js_web.createComponent)(Button, {
7620
- size: "small",
7621
- get disabled() {
7622
- return busy();
7623
- },
7624
- onClick: () => props.configure(key),
7625
- children: "Configure"
7626
- }), null);
7627
- (0, solid_js_web.insert)(_el$4, (0, solid_js_web.createComponent)(IconButton, {
7628
- icon: "close",
7629
- get label() {
7630
- return `Unpin ${props.label(pin())}`;
7631
- },
7632
- get disabled() {
7633
- return busy();
7634
- },
7635
- onClick: () => void run(() => props.remove(key))
7636
- }), null);
7637
- return _el$4;
7638
- })()
7639
- })
7640
- }));
7641
- return _el$2;
7642
- })()];
8018
+ get children() {
8019
+ return _tmpl$2$24();
8020
+ }
8021
+ }),
8022
+ (0, solid_js_web.createComponent)(GuiSortableList, {
8023
+ get ui() {
8024
+ return props.ui;
8025
+ },
8026
+ label: "Toolbar pin order",
8027
+ get items() {
8028
+ return props.pins;
8029
+ },
8030
+ itemKey: toolbarPinKey,
8031
+ get itemLabel() {
8032
+ return props.label;
8033
+ },
8034
+ scope: "toolbar",
8035
+ get disabled() {
8036
+ return busy() || !props.current();
8037
+ },
8038
+ move: (from, to) => void run(() => props.move(from, to)),
8039
+ children: (pin, handle) => (() => {
8040
+ var _el$3 = _tmpl$4$7(), _el$4 = _el$3.firstChild, _el$5 = _el$4.firstChild;
8041
+ (0, solid_js_web.insert)(_el$5, () => props.label(pin()));
8042
+ (0, solid_js_web.insert)(_el$4, (0, solid_js_web.createComponent)(solid_js.Show, {
8043
+ get when() {
8044
+ return source(pin());
8045
+ },
8046
+ get children() {
8047
+ var _el$6 = _tmpl$3$12();
8048
+ (0, solid_js_web.insert)(_el$6, () => source(pin()));
8049
+ return _el$6;
8050
+ }
8051
+ }), null);
8052
+ (0, solid_js_web.insert)(_el$3, handle, null);
8053
+ (0, solid_js_web.insert)(_el$3, (0, solid_js_web.createComponent)(Button, {
8054
+ size: "small",
8055
+ get disabled() {
8056
+ return busy();
8057
+ },
8058
+ onClick: () => props.configure(toolbarPinKey(pin())),
8059
+ children: "Configure"
8060
+ }), null);
8061
+ (0, solid_js_web.insert)(_el$3, (0, solid_js_web.createComponent)(IconButton, {
8062
+ icon: "close",
8063
+ get label() {
8064
+ return `Unpin ${props.label(pin())}`;
8065
+ },
8066
+ get disabled() {
8067
+ return busy();
8068
+ },
8069
+ onClick: () => void run(() => props.remove(toolbarPinKey(pin())))
8070
+ }), null);
8071
+ return _el$3;
8072
+ })()
8073
+ })
8074
+ ];
7643
8075
  }
7644
8076
  });
7645
8077
  }
@@ -7760,8 +8192,8 @@ function createMeasuredToolbar() {
7760
8192
  };
7761
8193
  }
7762
8194
  // src/features/pinned-toolbar/ui/gui/toolbar-button.tsx
7763
- var _tmpl$$31 = /*#__PURE__*/ (0, solid_js_web.template)(`<span style=position:absolute;width:1px;height:1px;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap>`);
7764
- var _tmpl$2$22 = /*#__PURE__*/ (0, solid_js_web.template)(`<span aria-hidden=true style=display:inline-flex;gap:4px;align-items:center;min-width:0;max-width:100%><span style=white-space:nowrap;overflow:hidden;text-overflow:ellipsis;min-width:0>`);
8195
+ var _tmpl$$32 = /*#__PURE__*/ (0, solid_js_web.template)(`<span style=position:absolute;width:1px;height:1px;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap>`);
8196
+ var _tmpl$2$23 = /*#__PURE__*/ (0, solid_js_web.template)(`<span aria-hidden=true style=display:inline-flex;gap:4px;align-items:center;min-width:0;max-width:100%><span style=white-space:nowrap;overflow:hidden;text-overflow:ellipsis;min-width:0>`);
7765
8197
  var _tmpl$3$11 = /*#__PURE__*/ (0, solid_js_web.template)(`<span style=display:inline-flex;min-width:0;flex-shrink:0>`);
7766
8198
  function GuiToolbarButton(props) {
7767
8199
  const Button = props.ui.Button;
@@ -7783,11 +8215,11 @@ function GuiToolbarButton(props) {
7783
8215
  },
7784
8216
  get children() {
7785
8217
  return [(() => {
7786
- var _el$ = _tmpl$$31();
8218
+ var _el$ = _tmpl$$32();
7787
8219
  (0, solid_js_web.insert)(_el$, label);
7788
8220
  return _el$;
7789
8221
  })(), (() => {
7790
- var _el$2 = _tmpl$2$22(), _el$3 = _el$2.firstChild;
8222
+ var _el$2 = _tmpl$2$23(), _el$3 = _el$2.firstChild;
7791
8223
  (0, solid_js_web.insert)(_el$2, (0, solid_js_web.createComponent)(solid_js.For, {
7792
8224
  get each() {
7793
8225
  return view().icons;
@@ -7846,8 +8278,8 @@ function GuiToolbarButton(props) {
7846
8278
  }
7847
8279
  (0, solid_js_web.delegateEvents)(["contextmenu", "keydown"]);
7848
8280
  // src/features/pinned-toolbar/ui/gui/toolbar.tsx
7849
- var _tmpl$$30 = /*#__PURE__*/ (0, solid_js_web.template)(`<span data-toolbar-visible>`);
7850
- var _tmpl$2$21 = /*#__PURE__*/ (0, solid_js_web.template)(`<div data-navigator-toolbar role=toolbar tabindex=-1 aria-label="Navigator pins"style="position:relative;display:flex;gap:4px;align-items:center;justify-content:center;padding:0 4px;min-height:28px;margin-bottom:8px"><div aria-hidden=true inert style=position:absolute;left:0;top:0;width:0;height:0;overflow:hidden;visibility:hidden;pointer-events:none><div style=display:flex;gap:4px;width:max-content><span>`);
8281
+ var _tmpl$$31 = /*#__PURE__*/ (0, solid_js_web.template)(`<span data-toolbar-visible>`);
8282
+ var _tmpl$2$22 = /*#__PURE__*/ (0, solid_js_web.template)(`<div data-navigator-toolbar role=toolbar tabindex=-1 aria-label="Navigator pins"style="position:relative;display:flex;gap:4px;align-items:center;justify-content:center;padding:0 4px;min-height:28px;margin-bottom:8px"><div aria-hidden=true inert style=position:absolute;left:0;top:0;width:0;height:0;overflow:hidden;visibility:hidden;pointer-events:none><div style=display:flex;gap:4px;width:max-content><span>`);
7851
8283
  function navigate(event) {
7852
8284
  if (event.defaultPrevented || event.key !== "ArrowLeft" && event.key !== "ArrowRight") return;
7853
8285
  const buttons = [...event.currentTarget.querySelectorAll(":scope [data-toolbar-visible] button")];
@@ -7871,7 +8303,7 @@ function GuiPinnedToolbar(props) {
7871
8303
  return keys().length > 0;
7872
8304
  },
7873
8305
  get children() {
7874
- var _el$ = _tmpl$2$21(), _el$3 = _el$.firstChild, _el$4 = _el$3.firstChild, _el$5 = _el$4.firstChild;
8306
+ var _el$ = _tmpl$2$22(), _el$3 = _el$.firstChild, _el$4 = _el$3.firstChild, _el$5 = _el$4.firstChild;
7875
8307
  _el$.$$keydown = navigate;
7876
8308
  var _ref$ = layout.root;
7877
8309
  typeof _ref$ === "function" ? (0, solid_js_web.use)(_ref$, _el$) : layout.root = _el$;
@@ -7907,7 +8339,7 @@ function GuiPinnedToolbar(props) {
7907
8339
  return hidden().length > 0;
7908
8340
  },
7909
8341
  get children() {
7910
- var _el$2 = _tmpl$$30();
8342
+ var _el$2 = _tmpl$$31();
7911
8343
  (0, solid_js_web.insert)(_el$2, (0, solid_js_web.createComponent)(Menu, {
7912
8344
  label: "More toolbar items",
7913
8345
  trigger: "icon",
@@ -7998,7 +8430,7 @@ function NavigatorPinnedToolbar() {
7998
8430
  });
7999
8431
  }
8000
8432
  // src/pages/navigator/ui/gui/monitoring-content.tsx
8001
- var _tmpl$$29 = /*#__PURE__*/ (0, solid_js_web.template)(`<div data-navigator-content style=padding:12px;overflow-y:auto;min-height:0;flex:1;font-size:13px>`);
8433
+ var _tmpl$$30 = /*#__PURE__*/ (0, solid_js_web.template)(`<div data-navigator-content style=padding:12px;overflow-y:auto;min-height:0;flex:1;font-size:13px>`);
8002
8434
  function MonitoringContent(props) {
8003
8435
  let body;
8004
8436
  (0, solid_js.onMount)(() => {
@@ -8007,7 +8439,7 @@ function MonitoringContent(props) {
8007
8439
  return (0, solid_js_web.createComponent)(NavigatorGuiContext.Provider, {
8008
8440
  value: props,
8009
8441
  get children() {
8010
- var _el$ = _tmpl$$29();
8442
+ var _el$ = _tmpl$$30();
8011
8443
  _el$.addEventListener("scroll", (event) => props.onScroll?.(event.currentTarget.scrollTop));
8012
8444
  (0, solid_js_web.use)((node) => {
8013
8445
  body = node;
@@ -8662,7 +9094,7 @@ function createMiniWindowInteraction(props) {
8662
9094
  };
8663
9095
  }
8664
9096
  // src/pages/navigator/ui/gui/mini-window.tsx
8665
- var _tmpl$$28 = /*#__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:flex;align-items:center;gap:4px;padding:8px;flex-wrap:wrap;cursor:move;touch-action:none;user-select:none><span data-navigator-move title="Drag or use arrow keys; Shift moves ten pixels"></span><strong style=flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap></strong></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>`);
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:flex;align-items:center;gap:4px;padding:8px;flex-wrap:wrap;cursor:move;touch-action:none;user-select:none><span data-navigator-move title="Drag or use arrow keys; Shift moves ten pixels"></span><strong style=flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap></strong></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>`);
8666
9098
  function NavigatorMiniWindow(props) {
8667
9099
  const Button = props.ui.Button;
8668
9100
  const IconButton = props.ui.IconButton;
@@ -8673,7 +9105,7 @@ function NavigatorMiniWindow(props) {
8673
9105
  interaction.start(event, "move");
8674
9106
  }
8675
9107
  return (() => {
8676
- var _el$ = _tmpl$$28(), _el$2 = _el$.firstChild, _el$3 = _el$2.firstChild, _el$4 = _el$3.nextSibling, _el$5 = _el$2.nextSibling, _el$6 = _el$5.firstChild;
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$6 = _el$5.firstChild;
8677
9109
  (0, solid_js_web.addEventListener)(_el$2, "lostpointercapture", interaction.end);
8678
9110
  (0, solid_js_web.addEventListener)(_el$2, "pointercancel", interaction.end);
8679
9111
  (0, solid_js_web.addEventListener)(_el$2, "pointerup", interaction.end, true);
@@ -8761,13 +9193,13 @@ function NavigatorMiniWindow(props) {
8761
9193
  "keydown"
8762
9194
  ]);
8763
9195
  // src/pages/navigator/ui/gui/monitoring-panel.tsx
8764
- var _tmpl$$27 = /*#__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:flex;gap:4px;align-items:center"><strong style=flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap>`);
8765
- var _tmpl$2$20 = /*#__PURE__*/ (0, solid_js_web.template)(`<div style=padding:12px><p>Navigator is in its mini-window.`);
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:flex;gap:4px;align-items:center"><strong style=flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap>`);
9197
+ var _tmpl$2$21 = /*#__PURE__*/ (0, solid_js_web.template)(`<div style=padding:12px><p>Navigator is in its mini-window.`);
8766
9198
  var _tmpl$3$10 = /*#__PURE__*/ (0, solid_js_web.template)(`<p role=status>Loading Navigator…`);
8767
9199
  function MonitoringPanel(props) {
8768
9200
  const Button = props.ui.Button;
8769
9201
  return (() => {
8770
- var _el$ = _tmpl$$27(), _el$2 = _el$.firstChild, _el$3 = _el$2.firstChild;
9202
+ var _el$ = _tmpl$$28(), _el$2 = _el$.firstChild, _el$3 = _el$2.firstChild;
8771
9203
  (0, solid_js_web.insert)(_el$3, () => props.title);
8772
9204
  (0, solid_js_web.insert)(_el$2, (0, solid_js_web.createComponent)(Button, {
8773
9205
  size: "small",
@@ -8812,7 +9244,7 @@ function MonitoringPanel(props) {
8812
9244
  },
8813
9245
  get fallback() {
8814
9246
  return (() => {
8815
- var _el$4 = _tmpl$2$20();
9247
+ var _el$4 = _tmpl$2$21();
8816
9248
  _el$4.firstChild;
8817
9249
  (0, solid_js_web.insert)(_el$4, (0, solid_js_web.createComponent)(Button, {
8818
9250
  size: "small",
@@ -8877,9 +9309,23 @@ function parseChangelog(source) {
8877
9309
  function changesSince(source, previous, current) {
8878
9310
  return parseChangelog(source).filter((entry) => entry.changes.length > 0 && isNewerVersion(entry.version, previous) && !isNewerVersion(entry.version, current));
8879
9311
  }
9312
+ // src/entities/navigator-release/model/update-progress.ts
9313
+ function updateProgressView(progress) {
9314
+ const labels = {
9315
+ preparing: "Preparing",
9316
+ downloading: "Downloading",
9317
+ installing: "Downloading / installing",
9318
+ verifying: "Verifying"
9319
+ };
9320
+ const fraction = progress.total !== void 0 && Number.isFinite(progress.total) && progress.total > 0 && progress.received !== void 0 && Number.isFinite(progress.received) && progress.received >= 0 ? Math.min(1, progress.received / progress.total) : void 0;
9321
+ return {
9322
+ label: fraction === void 0 ? labels[progress.phase] : `${labels[progress.phase]} ${Math.floor(fraction * 100)}%`,
9323
+ fraction
9324
+ };
9325
+ }
8880
9326
  // src/features/sidebar-settings/ui/gui/mcp-preset-menu.tsx
8881
- var _tmpl$$26 = /*#__PURE__*/ (0, solid_js_web.template)(`<ul style="margin:8px 0;padding:0;list-style:none">`);
8882
- var _tmpl$2$19 = /*#__PURE__*/ (0, solid_js_web.template)(`<li>No matching saved presets.`);
9327
+ var _tmpl$$27 = /*#__PURE__*/ (0, solid_js_web.template)(`<ul style="margin:8px 0;padding:0;list-style:none">`);
9328
+ var _tmpl$2$20 = /*#__PURE__*/ (0, solid_js_web.template)(`<li>No matching saved presets.`);
8883
9329
  var _tmpl$3$9 = /*#__PURE__*/ (0, solid_js_web.template)(`<li>`);
8884
9330
  function GuiMcpPresetMenu(props) {
8885
9331
  const Dialog = props.ui.Dialog;
@@ -8912,13 +9358,13 @@ function GuiMcpPresetMenu(props) {
8912
9358
  autofocus: true,
8913
9359
  "class": "w-full"
8914
9360
  }), (() => {
8915
- var _el$ = _tmpl$$26();
9361
+ var _el$ = _tmpl$$27();
8916
9362
  (0, solid_js_web.insert)(_el$, (0, solid_js_web.createComponent)(solid_js.For, {
8917
9363
  get each() {
8918
9364
  return names();
8919
9365
  },
8920
9366
  get fallback() {
8921
- return _tmpl$2$19();
9367
+ return _tmpl$2$20();
8922
9368
  },
8923
9369
  children: (name) => (() => {
8924
9370
  var _el$3 = _tmpl$3$9();
@@ -8936,8 +9382,8 @@ function GuiMcpPresetMenu(props) {
8936
9382
  });
8937
9383
  }
8938
9384
  // src/features/sidebar-settings/ui/gui/mcp-preview-rows.tsx
8939
- var _tmpl$$25 = /*#__PURE__*/ (0, solid_js_web.template)(`<section><h3></h3><ul style=padding:0;list-style:none>`);
8940
- var _tmpl$2$18 = /*#__PURE__*/ (0, solid_js_web.template)(`<li style="padding:6px 0;overflow-wrap:anywhere"><strong></strong><p style="margin:2px 0;opacity:0.65"> · `);
9385
+ var _tmpl$$26 = /*#__PURE__*/ (0, solid_js_web.template)(`<section><h3></h3><ul style=padding:0;list-style:none>`);
9386
+ var _tmpl$2$19 = /*#__PURE__*/ (0, solid_js_web.template)(`<li style="padding:6px 0;overflow-wrap:anywhere"><strong></strong><p style="margin:2px 0;opacity:0.65"> · `);
8941
9387
  var groups = [
8942
9388
  "Changes",
8943
9389
  "Skipped",
@@ -8955,7 +9401,7 @@ function GuiMcpPreviewRows(props) {
8955
9401
  return props.model.preview().rows.some((row) => group(row.change) === section);
8956
9402
  },
8957
9403
  get children() {
8958
- var _el$ = _tmpl$$25(), _el$2 = _el$.firstChild, _el$3 = _el$2.nextSibling;
9404
+ var _el$ = _tmpl$$26(), _el$2 = _el$.firstChild, _el$3 = _el$2.nextSibling;
8959
9405
  (0, solid_js_web.insert)(_el$2, section);
8960
9406
  (0, solid_js_web.insert)(_el$3, (0, solid_js_web.createComponent)(solid_js.For, {
8961
9407
  get each() {
@@ -8964,7 +9410,7 @@ function GuiMcpPreviewRows(props) {
8964
9410
  children: (name) => {
8965
9411
  const row = () => props.model.preview().rows.find((item) => item.name === name);
8966
9412
  return (() => {
8967
- var _el$4 = _tmpl$2$18(), _el$5 = _el$4.firstChild, _el$6 = _el$5.nextSibling, _el$7 = _el$6.firstChild;
9413
+ var _el$4 = _tmpl$2$19(), _el$5 = _el$4.firstChild, _el$6 = _el$5.nextSibling, _el$7 = _el$6.firstChild;
8968
9414
  (0, solid_js_web.insert)(_el$5, name);
8969
9415
  (0, solid_js_web.insert)(_el$6, () => row().status ?? "Not available", _el$7);
8970
9416
  (0, solid_js_web.insert)(_el$6, () => row().change, null);
@@ -8982,8 +9428,8 @@ function GuiMcpPreviewRows(props) {
8982
9428
  });
8983
9429
  }
8984
9430
  // src/features/sidebar-settings/ui/gui/mcp-preset-preview.tsx
8985
- var _tmpl$$24 = /*#__PURE__*/ (0, solid_js_web.template)(`<p>`);
8986
- var _tmpl$2$17 = /*#__PURE__*/ (0, solid_js_web.template)(`<p role=alert>`);
9431
+ var _tmpl$$25 = /*#__PURE__*/ (0, solid_js_web.template)(`<p>`);
9432
+ var _tmpl$2$18 = /*#__PURE__*/ (0, solid_js_web.template)(`<p role=alert>`);
8987
9433
  function GuiMcpPresetPreview(props) {
8988
9434
  const Dialog = props.ui.Dialog;
8989
9435
  const Button = props.ui.Button;
@@ -9044,7 +9490,7 @@ function GuiMcpPresetPreview(props) {
9044
9490
  get children() {
9045
9491
  return [
9046
9492
  (() => {
9047
- var _el$ = _tmpl$$24();
9493
+ var _el$ = _tmpl$$25();
9048
9494
  (0, solid_js_web.insert)(_el$, () => props.persistent ? "Desired states will be remembered for this scope, including unavailable servers." : "MCP persistence is off; desired states will not be saved.");
9049
9495
  return _el$;
9050
9496
  })(),
@@ -9053,7 +9499,7 @@ function GuiMcpPresetPreview(props) {
9053
9499
  return props.model.blocked() || error();
9054
9500
  },
9055
9501
  get children() {
9056
- var _el$2 = _tmpl$2$17();
9502
+ var _el$2 = _tmpl$2$18();
9057
9503
  (0, solid_js_web.insert)(_el$2, () => error() || props.model.blocked());
9058
9504
  return _el$2;
9059
9505
  }
@@ -9066,7 +9512,7 @@ function GuiMcpPresetPreview(props) {
9066
9512
  });
9067
9513
  }
9068
9514
  // src/features/sidebar-settings/ui/gui/settings-about.tsx
9069
- var _tmpl$$23 = /*#__PURE__*/ (0, solid_js_web.template)(`<p role=status>`);
9515
+ var _tmpl$$24 = /*#__PURE__*/ (0, solid_js_web.template)(`<p role=status>`);
9070
9516
  function GuiSettingsAbout(props) {
9071
9517
  const Section = props.ui.SettingsSection;
9072
9518
  const Row = props.ui.SettingsRow;
@@ -9076,11 +9522,15 @@ function GuiSettingsAbout(props) {
9076
9522
  const versions = () => props.about.changelog.filter((entry) => entry.changes.length > 0);
9077
9523
  const [version, setVersion] = (0, solid_js.createSignal)(versions()[0]?.version);
9078
9524
  const changes = () => versions().find((entry) => entry.version === version())?.changes.map((change) => `- ${change}`).join("\n") ?? "No user-facing release notes are bundled.";
9525
+ const progress = () => {
9526
+ const current = props.about.progress?.();
9527
+ return current && updateProgressView(current);
9528
+ };
9079
9529
  return [(0, solid_js_web.createComponent)(Section, {
9080
9530
  title: "About Navigator",
9081
9531
  get footer() {
9082
9532
  return (() => {
9083
- var _el$ = _tmpl$$23();
9533
+ var _el$ = _tmpl$$24();
9084
9534
  (0, solid_js_web.insert)(_el$, () => props.about.status());
9085
9535
  return _el$;
9086
9536
  })();
@@ -9089,7 +9539,17 @@ function GuiSettingsAbout(props) {
9089
9539
  return [
9090
9540
  (0, solid_js_web.createComponent)(Row, {
9091
9541
  get title() {
9092
- return `Navigator ${props.about.version}`;
9542
+ return (0, solid_js_web.memo)(() => !!progress())() ? (0, solid_js_web.createComponent)(GuiProgress, {
9543
+ get ui() {
9544
+ return props.ui;
9545
+ },
9546
+ get label() {
9547
+ return `Navigator · ${progress().label}`;
9548
+ },
9549
+ get value() {
9550
+ return progress().fraction;
9551
+ }
9552
+ }) : `Navigator ${props.about.version}`;
9093
9553
  },
9094
9554
  get description() {
9095
9555
  return `OpenCode Desktop ${props.about.hostVersion}. Experimental Desktop GUI.`;
@@ -9167,7 +9627,7 @@ function GuiSettingsAbout(props) {
9167
9627
  })];
9168
9628
  }
9169
9629
  // src/features/sidebar-settings/ui/gui/settings-behavior.tsx
9170
- var _tmpl$$22 = /*#__PURE__*/ (0, solid_js_web.template)(`<div style=display:flex;gap:8px;align-items:center>`);
9630
+ var _tmpl$$23 = /*#__PURE__*/ (0, solid_js_web.template)(`<div style=display:flex;gap:8px;align-items:center>`);
9171
9631
  function GuiSettingsBehavior(props) {
9172
9632
  const Section = props.ui.SettingsSection;
9173
9633
  const Row = props.ui.SettingsRow;
@@ -9251,7 +9711,7 @@ function GuiSettingsBehavior(props) {
9251
9711
  title: "Limits refresh",
9252
9712
  description: "Whole minutes, at least one. Manual refresh and model/account switches remain immediate.",
9253
9713
  get children() {
9254
- var _el$ = _tmpl$$22();
9714
+ var _el$ = _tmpl$$23();
9255
9715
  (0, solid_js_web.insert)(_el$, (0, solid_js_web.createComponent)(TextInput, {
9256
9716
  label: "Limits refresh in minutes",
9257
9717
  get value() {
@@ -9334,6 +9794,7 @@ function GuiSettingsBehavior(props) {
9334
9794
  ];
9335
9795
  }
9336
9796
  // src/features/sidebar-settings/ui/gui/settings-catalogs.tsx
9797
+ var _tmpl$$22 = /*#__PURE__*/ (0, solid_js_web.template)(`<span style=display:flex;gap:8px;align-items:center>`);
9337
9798
  function GuiSettingsCatalogs(props) {
9338
9799
  const Section = props.ui.SettingsSection;
9339
9800
  const Row = props.ui.SettingsRow;
@@ -9346,42 +9807,40 @@ function GuiSettingsCatalogs(props) {
9346
9807
  title: "Quick Actions",
9347
9808
  footer: "Visibility and order are scoped. Favorites are private and user-wide; usage never reorders actions.",
9348
9809
  get children() {
9349
- return (0, solid_js_web.createComponent)(solid_js.For, {
9350
- get each() {
9810
+ return (0, solid_js_web.createComponent)(GuiSortableList, {
9811
+ get ui() {
9812
+ return props.ui;
9813
+ },
9814
+ label: "Quick Action order",
9815
+ get items() {
9351
9816
  return props.catalogs.actions();
9352
9817
  },
9353
- children: (action, index) => (0, solid_js_web.createComponent)(Row, {
9818
+ itemKey: (action) => action.id,
9819
+ itemLabel: (action) => action.label,
9820
+ get scope() {
9821
+ return props.preferences.selectedScopeKey();
9822
+ },
9823
+ move: (from, to) => props.preferences.reorderQuickAction(from, to, props.preferences.selectedScopeKey()),
9824
+ children: (action, handle) => (0, solid_js_web.createComponent)(Row, {
9354
9825
  get title() {
9355
- return action.label;
9826
+ return (() => {
9827
+ var _el$ = _tmpl$$22();
9828
+ (0, solid_js_web.insert)(_el$, handle, null);
9829
+ (0, solid_js_web.insert)(_el$, () => action().label, null);
9830
+ return _el$;
9831
+ })();
9356
9832
  },
9357
9833
  get children() {
9358
- return [
9359
- (0, solid_js_web.createComponent)(Button, {
9360
- size: "small",
9361
- get disabled() {
9362
- return index() === 0;
9363
- },
9364
- onClick: () => props.preferences.moveQuickAction(action.id, -1),
9365
- children: "Move up"
9366
- }),
9367
- (0, solid_js_web.createComponent)(Button, {
9368
- size: "small",
9369
- get disabled() {
9370
- return index() === props.catalogs.actions().length - 1;
9371
- },
9372
- onClick: () => props.preferences.moveQuickAction(action.id, 1),
9373
- children: "Move down"
9374
- }),
9375
- (0, solid_js_web.createComponent)(Switch, {
9376
- get label() {
9377
- return `Show action ${action.label}`;
9378
- },
9379
- get checked() {
9380
- return props.preferences.selectedQuickActionVisible(action.id);
9381
- },
9382
- onChange: () => props.preferences.toggleQuickAction(action.id)
9383
- })
9384
- ];
9834
+ return (0, solid_js_web.createComponent)(Switch, {
9835
+ get label() {
9836
+ return `Show action ${action().label}`;
9837
+ },
9838
+ hideLabel: true,
9839
+ get checked() {
9840
+ return props.preferences.selectedQuickActionVisible(action().id);
9841
+ },
9842
+ onChange: () => props.preferences.toggleQuickAction(action().id)
9843
+ });
9385
9844
  }
9386
9845
  })
9387
9846
  });
@@ -9546,7 +10005,7 @@ function GuiPresetControls(props) {
9546
10005
  }
9547
10006
  // src/features/sidebar-settings/ui/gui/settings-presets.tsx
9548
10007
  var _tmpl$$20 = /*#__PURE__*/ (0, solid_js_web.template)(`<div style=display:flex;gap:8px;flex-wrap:wrap>`);
9549
- var _tmpl$2$16 = /*#__PURE__*/ (0, solid_js_web.template)(`<p role=status>`);
10008
+ var _tmpl$2$17 = /*#__PURE__*/ (0, solid_js_web.template)(`<p role=status>`);
9550
10009
  function GuiSettingsPresets(props) {
9551
10010
  const Section = props.ui.SettingsSection;
9552
10011
  const Row = props.ui.SettingsRow;
@@ -9573,7 +10032,7 @@ function GuiSettingsPresets(props) {
9573
10032
  return message();
9574
10033
  },
9575
10034
  get children() {
9576
- var _el$2 = _tmpl$2$16();
10035
+ var _el$2 = _tmpl$2$17();
9577
10036
  (0, solid_js_web.insert)(_el$2, message);
9578
10037
  return _el$2;
9579
10038
  }
@@ -9762,7 +10221,8 @@ function GuiSettingsResets(props) {
9762
10221
  });
9763
10222
  }
9764
10223
  // src/features/sidebar-settings/ui/gui/section-settings-row.tsx
9765
- var _tmpl$$19 = /*#__PURE__*/ (0, solid_js_web.template)(`<div role=group style=display:flex;gap:8px;align-items:center;flex-wrap:wrap>`);
10224
+ var _tmpl$$19 = /*#__PURE__*/ (0, solid_js_web.template)(`<div role=group style=display:flex;gap:8px;align-items:center;flex-wrap:wrap><span style=display:flex;gap:6px;align-items:center><span>Visible</span></span><span style=display:flex;gap:6px;align-items:center><span>Expanded`);
10225
+ var _tmpl$2$16 = /*#__PURE__*/ (0, solid_js_web.template)(`<span style=display:flex;gap:8px;align-items:center>`);
9766
10226
  function GuiSectionSettingsRow(props) {
9767
10227
  const Row = props.ui.SettingsRow;
9768
10228
  const Switch = props.ui.Switch;
@@ -9774,7 +10234,12 @@ function GuiSectionSettingsRow(props) {
9774
10234
  (0, solid_js.createEffect)(() => setLimit(String(props.preferences.selectedSectionItemLimit(props.section))));
9775
10235
  return (0, solid_js_web.createComponent)(Row, {
9776
10236
  get title() {
9777
- return label();
10237
+ return (() => {
10238
+ var _el$6 = _tmpl$2$16();
10239
+ (0, solid_js_web.insert)(_el$6, () => props.handle, null);
10240
+ (0, solid_js_web.insert)(_el$6, label, null);
10241
+ return _el$6;
10242
+ })();
9778
10243
  },
9779
10244
  get id() {
9780
10245
  return `navigator-section-${props.section}`;
@@ -9783,24 +10248,12 @@ function GuiSectionSettingsRow(props) {
9783
10248
  return props.section === "lsp" ? "LSP is not exposed by this Desktop API. Its saved layout is retained for supported TUI hosts." : void 0;
9784
10249
  },
9785
10250
  get children() {
9786
- var _el$ = _tmpl$$19();
9787
- (0, solid_js_web.insert)(_el$, (0, solid_js_web.createComponent)(Button, {
9788
- size: "small",
9789
- get disabled() {
9790
- return props.index === 0;
9791
- },
9792
- onClick: () => props.preferences.moveSelectedSection(props.section, -1),
9793
- children: "Move up"
9794
- }), null);
9795
- (0, solid_js_web.insert)(_el$, (0, solid_js_web.createComponent)(Button, {
9796
- size: "small",
9797
- get disabled() {
9798
- return props.index === props.count - 1;
9799
- },
9800
- onClick: () => props.preferences.moveSelectedSection(props.section, 1),
9801
- children: "Move down"
9802
- }), null);
9803
- (0, solid_js_web.insert)(_el$, (0, solid_js_web.createComponent)(Switch, {
10251
+ var _el$ = _tmpl$$19(), _el$2 = _el$.firstChild;
10252
+ _el$2.firstChild;
10253
+ var _el$4 = _el$2.nextSibling;
10254
+ _el$4.firstChild;
10255
+ (0, solid_js_web.insert)(_el$2, (0, solid_js_web.createComponent)(Switch, {
10256
+ hideLabel: true,
9804
10257
  get label() {
9805
10258
  return `Show ${label()}`;
9806
10259
  },
@@ -9809,7 +10262,8 @@ function GuiSectionSettingsRow(props) {
9809
10262
  },
9810
10263
  onChange: () => props.preferences.toggleSelectedSection(props.section)
9811
10264
  }), null);
9812
- (0, solid_js_web.insert)(_el$, (0, solid_js_web.createComponent)(Switch, {
10265
+ (0, solid_js_web.insert)(_el$4, (0, solid_js_web.createComponent)(Switch, {
10266
+ hideLabel: true,
9813
10267
  get label() {
9814
10268
  return `Expand ${label()}`;
9815
10269
  },
@@ -9857,18 +10311,25 @@ function GuiSettingsSections(props) {
9857
10311
  title: "Sections",
9858
10312
  footer: "Visibility changes apply immediately. Save this layout as the scoped default to use it in future sessions.",
9859
10313
  get children() {
9860
- return (0, solid_js_web.createComponent)(solid_js.For, {
9861
- get each() {
10314
+ return (0, solid_js_web.createComponent)(GuiSortableList, {
10315
+ get ui() {
10316
+ return props.ui;
10317
+ },
10318
+ label: "Section order",
10319
+ get items() {
9862
10320
  return preferences.selectedSectionOrder();
9863
10321
  },
9864
- children: (section, index) => (0, solid_js_web.createComponent)(GuiSectionSettingsRow, (0, solid_js_web.mergeProps)(props, {
9865
- section,
9866
- get index() {
9867
- return index();
10322
+ itemKey: (section) => section,
10323
+ itemLabel: (section) => SECTION_DEFINITIONS.find((value) => value.name === section)?.label ?? section,
10324
+ get scope() {
10325
+ return preferences.selectedScopeKey();
10326
+ },
10327
+ move: (from, to) => preferences.reorderSelectedSection(from, to, preferences.selectedScopeKey()),
10328
+ children: (section, handle) => (0, solid_js_web.createComponent)(GuiSectionSettingsRow, (0, solid_js_web.mergeProps)(props, {
10329
+ get section() {
10330
+ return section();
9868
10331
  },
9869
- get count() {
9870
- return preferences.selectedSectionOrder().length;
9871
- }
10332
+ handle
9872
10333
  }))
9873
10334
  });
9874
10335
  }
@@ -9902,103 +10363,105 @@ function GuiNavigatorSettings(props) {
9902
10363
  title: "Navigator",
9903
10364
  description: "Shared sidebar settings for this Desktop and your local TUI instances.",
9904
10365
  get children() {
9905
- return (0, solid_js_web.createComponent)(solid_js.Show, {
9906
- get when() {
9907
- return props.preferences.ready();
9908
- },
9909
- get fallback() {
9910
- return _tmpl$$18();
9911
- },
9912
- get children() {
9913
- return [
9914
- (0, solid_js_web.createComponent)(Section, {
9915
- title: "Preference scope",
9916
- get footer() {
9917
- return (0, solid_js_web.createComponent)(solid_js.Show, {
9918
- get when() {
9919
- return status();
9920
- },
9921
- get children() {
9922
- var _el$2 = _tmpl$2$15();
9923
- (0, solid_js_web.insert)(_el$2, status);
9924
- return _el$2;
9925
- }
9926
- });
9927
- },
9928
- get children() {
9929
- return [
9930
- (0, solid_js_web.createComponent)(Row, {
9931
- title: "Scope",
9932
- description: "Global applies everywhere. Worktree overrides use the currently selected server and location.",
9933
- get children() {
9934
- return (0, solid_js_web.createComponent)(Select, {
9935
- label: "Navigator preference scope",
9936
- get value() {
9937
- return props.preferences.preferenceScope();
9938
- },
9939
- get options() {
9940
- return [{
9941
- value: "global",
9942
- label: "Global"
9943
- }, ...props.preferences.canUseWorktreeScope() ? [{
9944
- value: "worktree",
9945
- label: "Worktree"
9946
- }] : []];
9947
- },
9948
- get onChange() {
9949
- return props.preferences.setPreferenceScope;
9950
- }
9951
- });
9952
- }
9953
- }),
9954
- (0, solid_js_web.createComponent)(Row, {
9955
- title: "Layout default",
9956
- description: "Changing section visibility or order does not implicitly replace the saved default.",
9957
- get children() {
9958
- return (0, solid_js_web.createComponent)(Button, {
9959
- get busy() {
9960
- return busy();
9961
- },
9962
- onClick: () => void run(props.preferences.saveLayoutAsDefault, "Layout default saved for this scope."),
9963
- children: "Save layout as default"
9964
- });
9965
- }
9966
- }),
9967
- (0, solid_js_web.createComponent)(Row, {
9968
- title: "Reload private preferences",
9969
- description: "Flush local writes, then load changes from other Navigator instances. Temporary layout overrides are cleared.",
10366
+ return (0, solid_js_web.createComponent)(GuiSettingsSurface, { get children() {
10367
+ return (0, solid_js_web.createComponent)(solid_js.Show, {
10368
+ get when() {
10369
+ return props.preferences.ready();
10370
+ },
10371
+ get fallback() {
10372
+ return _tmpl$$18();
10373
+ },
10374
+ get children() {
10375
+ return [
10376
+ (0, solid_js_web.createComponent)(Section, {
10377
+ title: "Preference scope",
10378
+ get footer() {
10379
+ return (0, solid_js_web.createComponent)(solid_js.Show, {
10380
+ get when() {
10381
+ return status();
10382
+ },
9970
10383
  get children() {
9971
- return (0, solid_js_web.createComponent)(Button, {
9972
- get busy() {
9973
- return busy();
9974
- },
9975
- onClick: () => void run(props.preferences.reloadFromFile, "Private preferences reloaded."),
9976
- children: "Reload preferences"
9977
- });
10384
+ var _el$2 = _tmpl$2$15();
10385
+ (0, solid_js_web.insert)(_el$2, status);
10386
+ return _el$2;
9978
10387
  }
9979
- })
9980
- ];
9981
- }
9982
- }),
9983
- (0, solid_js_web.createComponent)(GuiSettingsSections, props),
9984
- (0, solid_js_web.createComponent)(GuiSettingsBehavior, props),
9985
- (0, solid_js_web.createComponent)(GuiSettingsPresets, props),
9986
- (0, solid_js_web.createComponent)(GuiSettingsCatalogs, props),
9987
- (0, solid_js_web.createComponent)(GuiSettingsResets, props),
9988
- (0, solid_js_web.createComponent)(GuiSettingsAbout, {
9989
- get ui() {
9990
- return props.ui;
9991
- },
9992
- get about() {
9993
- return props.about;
9994
- },
9995
- get showGuide() {
9996
- return props.showGuide;
9997
- }
9998
- })
9999
- ];
10000
- }
10001
- });
10388
+ });
10389
+ },
10390
+ get children() {
10391
+ return [
10392
+ (0, solid_js_web.createComponent)(Row, {
10393
+ title: "Scope",
10394
+ description: "Global applies everywhere. Worktree overrides use the currently selected server and location.",
10395
+ get children() {
10396
+ return (0, solid_js_web.createComponent)(Select, {
10397
+ label: "Navigator preference scope",
10398
+ get value() {
10399
+ return props.preferences.preferenceScope();
10400
+ },
10401
+ get options() {
10402
+ return [{
10403
+ value: "global",
10404
+ label: "Global"
10405
+ }, ...props.preferences.canUseWorktreeScope() ? [{
10406
+ value: "worktree",
10407
+ label: "Worktree"
10408
+ }] : []];
10409
+ },
10410
+ get onChange() {
10411
+ return props.preferences.setPreferenceScope;
10412
+ }
10413
+ });
10414
+ }
10415
+ }),
10416
+ (0, solid_js_web.createComponent)(Row, {
10417
+ title: "Layout default",
10418
+ description: "Changing section visibility or order does not implicitly replace the saved default.",
10419
+ get children() {
10420
+ return (0, solid_js_web.createComponent)(Button, {
10421
+ get busy() {
10422
+ return busy();
10423
+ },
10424
+ onClick: () => void run(props.preferences.saveLayoutAsDefault, "Layout default saved for this scope."),
10425
+ children: "Save layout as default"
10426
+ });
10427
+ }
10428
+ }),
10429
+ (0, solid_js_web.createComponent)(Row, {
10430
+ title: "Reload private preferences",
10431
+ description: "Flush local writes, then load changes from other Navigator instances. Temporary layout overrides are cleared.",
10432
+ get children() {
10433
+ return (0, solid_js_web.createComponent)(Button, {
10434
+ get busy() {
10435
+ return busy();
10436
+ },
10437
+ onClick: () => void run(props.preferences.reloadFromFile, "Private preferences reloaded."),
10438
+ children: "Reload preferences"
10439
+ });
10440
+ }
10441
+ })
10442
+ ];
10443
+ }
10444
+ }),
10445
+ (0, solid_js_web.createComponent)(GuiSettingsSections, props),
10446
+ (0, solid_js_web.createComponent)(GuiSettingsBehavior, props),
10447
+ (0, solid_js_web.createComponent)(GuiSettingsPresets, props),
10448
+ (0, solid_js_web.createComponent)(GuiSettingsCatalogs, props),
10449
+ (0, solid_js_web.createComponent)(GuiSettingsResets, props),
10450
+ (0, solid_js_web.createComponent)(GuiSettingsAbout, {
10451
+ get ui() {
10452
+ return props.ui;
10453
+ },
10454
+ get about() {
10455
+ return props.about;
10456
+ },
10457
+ get showGuide() {
10458
+ return props.showGuide;
10459
+ }
10460
+ })
10461
+ ];
10462
+ }
10463
+ });
10464
+ } });
10002
10465
  }
10003
10466
  });
10004
10467
  }
@@ -10604,7 +11067,7 @@ function createGuiBugReport(context) {
10604
11067
  let token = "";
10605
11068
  (0, solid_js.onCleanup)(() => abort.abort());
10606
11069
  const model = createBugReportModel({
10607
- navigatorVersion: "0.27.1",
11070
+ navigatorVersion: "0.27.2",
10608
11071
  openCodeVersion: context.app.version,
10609
11072
  platform: context.app.platform,
10610
11073
  runtime: "OpenCode Desktop GUI"
@@ -10656,8 +11119,8 @@ function createGuiBugReport(context) {
10656
11119
  }
10657
11120
  // src/app/gui/release.ts
10658
11121
  var guiRelease = {
10659
- version: "0.27.1",
10660
- changelog: "# Changelog\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"
11122
+ version: "0.27.2",
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"
10661
11124
  };
10662
11125
  // src/app/gui/about.ts
10663
11126
  function createGuiAbout(context) {
@@ -10665,13 +11128,18 @@ function createGuiAbout(context) {
10665
11128
  const [busy, setBusy] = (0, solid_js.createSignal)(false);
10666
11129
  const [status, setStatus] = (0, solid_js.createSignal)("Updates have not been checked.");
10667
11130
  const [token, setToken] = (0, solid_js.createSignal)();
11131
+ const progress = () => {
11132
+ const current = ipc.state();
11133
+ return current && current.phase !== "idle" ? { phase: current.phase } : void 0;
11134
+ };
10668
11135
  return {
10669
11136
  report: createGuiBugReport(context),
10670
11137
  version: guiRelease.version,
10671
11138
  hostVersion: context.app?.version ?? "unknown",
10672
11139
  changelog: parseChangelog(guiRelease.changelog),
10673
11140
  status,
10674
- busy,
11141
+ busy: () => busy() || Boolean(progress()),
11142
+ progress,
10675
11143
  available: () => Boolean(token()),
10676
11144
  async check() {
10677
11145
  if (busy()) return;
@@ -14063,10 +14531,11 @@ function createGuiPresetDialogs(context, preferences, registry, mcp) {
14063
14531
  };
14064
14532
  }
14065
14533
  // src/features/search-everything/ui/gui/result-row.tsx
14066
- var _tmpl$$7 = /*#__PURE__*/ (0, solid_js_web.template)(`<span role=status>Working…`);
14534
+ var _tmpl$$7 = /*#__PURE__*/ (0, solid_js_web.template)(`<span role=status style=display:inline-flex;gap:6px;align-items:center>Working…`);
14067
14535
  var _tmpl$2$6 = /*#__PURE__*/ (0, solid_js_web.template)(`<li style="display:flex;gap:4px;align-items:center;min-width:0;padding:3px 0"><button type=button style=flex:1;min-width:0;text-align:left;padding:8px;color:inherit;border:0;border-radius:6px><strong style=display:block;overflow-wrap:anywhere></strong><span style=display:block;opacity:0.65;font-size:12px;overflow-wrap:anywhere>`);
14068
14536
  function GuiSearchResultRow(props) {
14069
14537
  const Button = props.ui.Button;
14538
+ const Loader = props.ui.Loader;
14070
14539
  return (() => {
14071
14540
  var _el$ = _tmpl$2$6(), _el$2 = _el$.firstChild, _el$3 = _el$2.firstChild, _el$4 = _el$3.nextSibling;
14072
14541
  _el$2.$$click = (event) => {
@@ -14081,7 +14550,9 @@ function GuiSearchResultRow(props) {
14081
14550
  return props.busy;
14082
14551
  },
14083
14552
  get children() {
14084
- return _tmpl$$7();
14553
+ var _el$5 = _tmpl$$7(), _el$6 = _el$5.firstChild;
14554
+ (0, solid_js_web.insert)(_el$5, (0, solid_js_web.createComponent)(Loader, { size: "small" }), _el$6);
14555
+ return _el$5;
14085
14556
  }
14086
14557
  }), null);
14087
14558
  (0, solid_js_web.insert)(_el$, (0, solid_js_web.createComponent)(solid_js.Show, {
@@ -15287,12 +15758,12 @@ function createGuiToolbarDialogs(context, registry, preferences) {
15287
15758
  if (!current()) throw new DOMException("Toolbar target changed", "AbortError");
15288
15759
  await save(update);
15289
15760
  }
15290
- async function move(key, direction) {
15761
+ async function move(key, target) {
15291
15762
  const pins = preferences.toolbarPins();
15292
15763
  const index = pins.findIndex((pin) => toolbarPinKey(pin) === key);
15293
- const destination = index + direction;
15294
- if (index === -1 || destination < 0 || destination >= pins.length) return;
15295
- const before = pins[destination + (direction === 1 ? 1 : 0)];
15764
+ const destination = pins.findIndex((pin) => toolbarPinKey(pin) === target);
15765
+ if (index === -1 || destination === -1 || destination >= pins.length) return;
15766
+ const before = pins[destination + (destination > index ? 1 : 0)];
15296
15767
  await change({
15297
15768
  operation: "move",
15298
15769
  key,
@@ -15633,7 +16104,7 @@ var setup = (context) => {
15633
16104
  try {
15634
16105
  await preferences.flush();
15635
16106
  context.toast.show({
15636
- title: `Navigator 0.27.1`,
16107
+ title: `Navigator 0.27.2`,
15637
16108
  variant: "default"
15638
16109
  });
15639
16110
  } catch {