@rockysoft/opencode-hybrid-workflow 0.0.0-stage → 0.3.2-beta.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.
Files changed (156) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +163 -3
  3. package/THIRD_PARTY_NOTICES.md +18 -0
  4. package/assets/agents/backend-engineer.md +167 -0
  5. package/assets/agents/code-reviewer.md +129 -0
  6. package/assets/agents/database-engineer.md +162 -0
  7. package/assets/agents/devops-engineer.md +115 -0
  8. package/assets/agents/frontend-engineer.md +38 -0
  9. package/assets/agents/fullstack-architect.md +43 -0
  10. package/assets/agents/security-auditor.md +132 -0
  11. package/assets/agents/technical-writer.md +78 -0
  12. package/assets/agents/test-engineer.md +154 -0
  13. package/assets/rules.md +93 -0
  14. package/assets/skills/frontend-design/INSTALLATION.json +9 -0
  15. package/assets/skills/frontend-design/LICENSE.txt +177 -0
  16. package/assets/skills/frontend-design/SKILL.md +78 -0
  17. package/assets/skills/ui-ux-pro-max/INSTALLATION.json +10 -0
  18. package/assets/skills/ui-ux-pro-max/LICENSE +21 -0
  19. package/assets/skills/ui-ux-pro-max/SKILL.md +221 -0
  20. package/assets/skills/ui-ux-pro-max/data/app-interface.csv +33 -0
  21. package/assets/skills/ui-ux-pro-max/data/catalog-summary.json +78 -0
  22. package/assets/skills/ui-ux-pro-max/data/charts.csv +26 -0
  23. package/assets/skills/ui-ux-pro-max/data/colors.csv +193 -0
  24. package/assets/skills/ui-ux-pro-max/data/data-provenance.json +1348 -0
  25. package/assets/skills/ui-ux-pro-max/data/google-font-licenses.json +20185 -0
  26. package/assets/skills/ui-ux-pro-max/data/google-fonts.csv +1935 -0
  27. package/assets/skills/ui-ux-pro-max/data/icons.csv +106 -0
  28. package/assets/skills/ui-ux-pro-max/data/landing.csv +35 -0
  29. package/assets/skills/ui-ux-pro-max/data/motion.csv +18 -0
  30. package/assets/skills/ui-ux-pro-max/data/phosphor-icons-upstream.json +32582 -0
  31. package/assets/skills/ui-ux-pro-max/data/products.csv +193 -0
  32. package/assets/skills/ui-ux-pro-max/data/react-performance.csv +45 -0
  33. package/assets/skills/ui-ux-pro-max/data/stacks/angular.csv +51 -0
  34. package/assets/skills/ui-ux-pro-max/data/stacks/astro.csv +54 -0
  35. package/assets/skills/ui-ux-pro-max/data/stacks/avalonia.csv +57 -0
  36. package/assets/skills/ui-ux-pro-max/data/stacks/flutter.csv +53 -0
  37. package/assets/skills/ui-ux-pro-max/data/stacks/html-tailwind.csv +60 -0
  38. package/assets/skills/ui-ux-pro-max/data/stacks/javafx.csv +76 -0
  39. package/assets/skills/ui-ux-pro-max/data/stacks/jetpack-compose.csv +53 -0
  40. package/assets/skills/ui-ux-pro-max/data/stacks/laravel.csv +51 -0
  41. package/assets/skills/ui-ux-pro-max/data/stacks/nextjs.csv +62 -0
  42. package/assets/skills/ui-ux-pro-max/data/stacks/nuxt-ui.csv +77 -0
  43. package/assets/skills/ui-ux-pro-max/data/stacks/nuxtjs.csv +68 -0
  44. package/assets/skills/ui-ux-pro-max/data/stacks/react-native.csv +52 -0
  45. package/assets/skills/ui-ux-pro-max/data/stacks/react.csv +67 -0
  46. package/assets/skills/ui-ux-pro-max/data/stacks/shadcn.csv +69 -0
  47. package/assets/skills/ui-ux-pro-max/data/stacks/svelte.csv +56 -0
  48. package/assets/skills/ui-ux-pro-max/data/stacks/swiftui.csv +51 -0
  49. package/assets/skills/ui-ux-pro-max/data/stacks/threejs.csv +54 -0
  50. package/assets/skills/ui-ux-pro-max/data/stacks/uno.csv +60 -0
  51. package/assets/skills/ui-ux-pro-max/data/stacks/uwp.csv +56 -0
  52. package/assets/skills/ui-ux-pro-max/data/stacks/vue.csv +50 -0
  53. package/assets/skills/ui-ux-pro-max/data/stacks/winui.csv +60 -0
  54. package/assets/skills/ui-ux-pro-max/data/stacks/wpf.csv +57 -0
  55. package/assets/skills/ui-ux-pro-max/data/styles.csv +89 -0
  56. package/assets/skills/ui-ux-pro-max/data/typography.csv +75 -0
  57. package/assets/skills/ui-ux-pro-max/data/ui-reasoning.csv +193 -0
  58. package/assets/skills/ui-ux-pro-max/data/ux-guidelines.csv +120 -0
  59. package/assets/skills/ui-ux-pro-max/references/pro-rules.md +117 -0
  60. package/assets/skills/ui-ux-pro-max/references/quick-reference.md +256 -0
  61. package/assets/skills/ui-ux-pro-max/scripts/core.py +993 -0
  62. package/assets/skills/ui-ux-pro-max/scripts/design_system.py +1668 -0
  63. package/assets/skills/ui-ux-pro-max/scripts/reasoning_contract.py +123 -0
  64. package/assets/skills/ui-ux-pro-max/scripts/search.py +177 -0
  65. package/assets/skills/ui-ux-pro-max/scripts/tests/fixtures/catalogs/google-api.json +36 -0
  66. package/assets/skills/ui-ux-pro-max/scripts/tests/fixtures/catalogs/google-catalog.json +33 -0
  67. package/assets/skills/ui-ux-pro-max/scripts/tests/fixtures/catalogs/google-existing.csv +3 -0
  68. package/assets/skills/ui-ux-pro-max/scripts/tests/fixtures/catalogs/google-metadata.json +17 -0
  69. package/assets/skills/ui-ux-pro-max/scripts/tests/fixtures/catalogs/google-overrides.json +7 -0
  70. package/assets/skills/ui-ux-pro-max/scripts/tests/fixtures/catalogs/icons-curated.csv +4 -0
  71. package/assets/skills/ui-ux-pro-max/scripts/tests/fixtures/catalogs/phosphor-core.json +23 -0
  72. package/assets/skills/ui-ux-pro-max/scripts/tests/fixtures/catalogs/phosphor-package.json +13 -0
  73. package/assets/skills/ui-ux-pro-max/scripts/tests/fixtures/catalogs/phosphor-react-exports.json +4 -0
  74. package/assets/skills/ui-ux-pro-max/scripts/tests/fixtures/catalogs/phosphor-react-package.json +5 -0
  75. package/assets/skills/ui-ux-pro-max/scripts/tests/fixtures/relevance-baseline.json +3366 -0
  76. package/assets/skills/ui-ux-pro-max/scripts/tests/fixtures/relevance-cases.json +111 -0
  77. package/assets/skills/ui-ux-pro-max/scripts/tests/fixtures/relevance-thresholds.json +100 -0
  78. package/assets/skills/ui-ux-pro-max/scripts/tests/test_catalog_refresh.py +354 -0
  79. package/assets/skills/ui-ux-pro-max/scripts/tests/test_catalog_summary_line_endings.py +78 -0
  80. package/assets/skills/ui-ux-pro-max/scripts/tests/test_core.py +343 -0
  81. package/assets/skills/ui-ux-pro-max/scripts/tests/test_core_data_quality.py +198 -0
  82. package/assets/skills/ui-ux-pro-max/scripts/tests/test_data_contracts.py +421 -0
  83. package/assets/skills/ui-ux-pro-max/scripts/tests/test_design_system_mode.py +233 -0
  84. package/assets/skills/ui-ux-pro-max/scripts/tests/test_design_system_stack.py +61 -0
  85. package/assets/skills/ui-ux-pro-max/scripts/tests/test_native_desktop_stack_freshness.py +179 -0
  86. package/assets/skills/ui-ux-pro-max/scripts/tests/test_relevance_evaluator.py +182 -0
  87. package/assets/skills/ui-ux-pro-max/scripts/tests/test_skill_script_paths.py +82 -0
  88. package/assets/skills/ui-ux-pro-max/scripts/tests/test_style_taxonomy.py +175 -0
  89. package/assets/skills/ui-ux-pro-max/scripts/tests/test_text_layout_resilience.py +120 -0
  90. package/assets/skills/ui-ux-pro-max/scripts/tests/test_web_stack_freshness.py +177 -0
  91. package/assets/skills/ui-ux-pro-max/scripts/validate_data.py +1095 -0
  92. package/assets/skills/web-design-guidelines/INSTALLATION.json +1 -0
  93. package/assets/skills/web-design-guidelines/SKILL.md +18 -0
  94. package/cli.mjs +91 -0
  95. package/core/controller.mjs +367 -0
  96. package/core/dashboard-state.js +48 -0
  97. package/core/dashboard.css +2 -0
  98. package/core/dashboard.html +12 -0
  99. package/core/dashboard.js +72 -0
  100. package/core/decision.mjs +22 -0
  101. package/core/design.mjs +139 -0
  102. package/core/evidence.mjs +82 -0
  103. package/core/frontend-policy.mjs +34 -0
  104. package/core/images.mjs +35 -0
  105. package/core/monitor-data.mjs +58 -0
  106. package/core/monitor.mjs +24 -0
  107. package/core/operation-lock.mjs +82 -0
  108. package/core/plugin.mjs +91 -0
  109. package/core/posix-lock.mjs +31 -0
  110. package/core/posix-lock.py +23 -0
  111. package/core/pricing.mjs +53 -0
  112. package/core/process-identity.mjs +19 -0
  113. package/core/research-tools.mjs +37 -0
  114. package/core/review-context.mjs +43 -0
  115. package/core/snapshot.mjs +95 -0
  116. package/core/telemetry.mjs +107 -0
  117. package/core/workers.mjs +192 -0
  118. package/core/workflow-policy.mjs +10 -0
  119. package/docs/configuration.md +134 -0
  120. package/docs/images/01-install.png +0 -0
  121. package/docs/images/02-reviewers.png +0 -0
  122. package/docs/images/03-connection.png +0 -0
  123. package/docs/images/04-provider.png +0 -0
  124. package/docs/images/05-model.png +0 -0
  125. package/docs/images/06-effort.png +0 -0
  126. package/docs/images/07-design-lead.png +0 -0
  127. package/docs/images/08-save.png +0 -0
  128. package/docs/images/09-settings.png +0 -0
  129. package/docs/images/10-browser.png +0 -0
  130. package/docs/images/11-browser-confirm.png +0 -0
  131. package/docs/images/12-browser-ready.png +0 -0
  132. package/docs/images/13-tools.png +0 -0
  133. package/docs/images/14-diagnostics.png +0 -0
  134. package/docs/images/15-connect-provider.png +0 -0
  135. package/docs/images/16-reopen.png +0 -0
  136. package/docs/images/17-implementation.png +0 -0
  137. package/docs/images/18-cli.png +0 -0
  138. package/docs/images/19-cli-model.png +0 -0
  139. package/docs/images/20-cli-effort.png +0 -0
  140. package/index.js +19 -0
  141. package/lib/commands.mjs +48 -0
  142. package/lib/config.mjs +63 -0
  143. package/lib/install.mjs +111 -0
  144. package/lib/native-browser.mjs +79 -0
  145. package/lib/opencode-reviewer.mjs +129 -0
  146. package/lib/platform.mjs +14 -0
  147. package/lib/reviewer-browser-proxy.mjs +61 -0
  148. package/lib/reviewer-browser.mjs +35 -0
  149. package/lib/reviewers.mjs +11 -0
  150. package/lib/select-reviewers.mjs +58 -0
  151. package/lib/settings-rpc.mjs +9 -0
  152. package/lib/settings-service.mjs +129 -0
  153. package/package.json +64 -6
  154. package/sidebar/reader.mjs +80 -0
  155. package/sidebar/settings.mjs +99 -0
  156. package/tui.js +303 -0
package/tui.js ADDED
@@ -0,0 +1,303 @@
1
+ // Generated by npm run build; edit tui.tsx.
2
+ import { memo as _$memo } from "@opentui/solid";
3
+ import { createComponent as _$createComponent } from "@opentui/solid";
4
+ import { insert as _$insert } from "@opentui/solid";
5
+ import { effect as _$effect } from "@opentui/solid";
6
+ import { createTextNode as _$createTextNode } from "@opentui/solid";
7
+ import { insertNode as _$insertNode } from "@opentui/solid";
8
+ import { setProp as _$setProp } from "@opentui/solid";
9
+ import { createElement as _$createElement } from "@opentui/solid";
10
+ import { Plugin } from '@opencode/plugin/tui';
11
+ import { For, Show, createEffect, createMemo, createSignal, onCleanup } from 'solid-js';
12
+ import { readSettings } from './lib/config.mjs';
13
+ import { createReader, cards, number, money } from './sidebar/reader.mjs';
14
+ import { captureTotals } from './core/dashboard-state.js';
15
+ import { createSettingsUI } from './sidebar/settings.mjs';
16
+ export default Plugin.define({
17
+ id: 'personal.hybrid-usage',
18
+ setup(context) {
19
+ const preferences = createSettingsUI(context);
20
+ context.keymap.layer(() => ({
21
+ mode: 'global',
22
+ commands: [{
23
+ id: 'hybrid.settings',
24
+ title: 'Hybrid Workflow: settings',
25
+ group: 'Hybrid Workflow',
26
+ palette: true,
27
+ slash: {
28
+ name: 'hybrid'
29
+ },
30
+ run: () => preferences.show()
31
+ }]
32
+ }));
33
+ const home = context.ui.slot({
34
+ append: 'home.footer',
35
+ render: () => (() => {
36
+ var _el$ = _$createElement("text");
37
+ _$insertNode(_el$, _$createTextNode(`[Hybrid Workflow settings]`));
38
+ _$setProp(_el$, "onMouseDown", () => preferences.show());
39
+ _$effect(_$p => _$setProp(_el$, "fg", context.theme.text.muted, _$p));
40
+ return _el$;
41
+ })()
42
+ });
43
+ const firstRun = setTimeout(() => {
44
+ void preferences.show(true);
45
+ }, 750);
46
+ const config = readSettings(context.options);
47
+ const settings = {
48
+ ...config,
49
+ efforts: {
50
+ astra: config.codex?.variant ?? config.codex?.effort ?? 'default',
51
+ opus: config.claude?.variant ?? config.claude?.effort ?? 'default'
52
+ },
53
+ models: {
54
+ astra: config.codex?.model,
55
+ opus: config.claude?.model
56
+ }
57
+ };
58
+ const read = createReader(settings);
59
+ const [saved, update] = context.storage.store('totals', {
60
+ initial: {
61
+ resets: {}
62
+ }
63
+ });
64
+ function Usage(props) {
65
+ const [snapshot, setSnapshot] = createSignal(null);
66
+ const [error, setError] = createSignal('');
67
+ const location = createMemo(() => context.data.session.get(props.sessionID)?.location);
68
+ createEffect(() => {
69
+ const directory = location()?.directory;
70
+ let disposed = false,
71
+ busy = false;
72
+ setSnapshot(null);
73
+ setError('');
74
+ const poll = async () => {
75
+ if (busy || !directory) return;
76
+ busy = true;
77
+ try {
78
+ const next = await read(directory);
79
+ if (!disposed) {
80
+ setSnapshot(next);
81
+ setError('');
82
+ }
83
+ } catch {
84
+ if (!disposed) {
85
+ setSnapshot(null);
86
+ setError('Telemetry unavailable');
87
+ }
88
+ } finally {
89
+ busy = false;
90
+ }
91
+ };
92
+ void poll();
93
+ const timer = setInterval(poll, 3000);
94
+ onCleanup(() => {
95
+ disposed = true;
96
+ clearInterval(timer);
97
+ });
98
+ });
99
+ const totals = createMemo(() => snapshot() ? cards(snapshot(), saved.resets[snapshot().key]) : []);
100
+ async function clear() {
101
+ const value = snapshot();
102
+ if (!value) return;
103
+ try {
104
+ await update(draft => {
105
+ draft.resets[value.key] = captureTotals(value.calls);
106
+ });
107
+ } catch {
108
+ context.ui.toast.show({
109
+ message: 'Could not save usage reset',
110
+ variant: 'error'
111
+ });
112
+ }
113
+ }
114
+ async function restore() {
115
+ const value = snapshot();
116
+ if (!value) return;
117
+ try {
118
+ await update(draft => {
119
+ delete draft.resets[value.key];
120
+ });
121
+ } catch {
122
+ context.ui.toast.show({
123
+ message: 'Could not restore usage totals',
124
+ variant: 'error'
125
+ });
126
+ }
127
+ }
128
+ context.keymap.layer(() => ({
129
+ mode: 'global',
130
+ commands: [{
131
+ id: 'hybrid-usage.clear',
132
+ title: 'Hybrid usage: clear totals for this project',
133
+ palette: true,
134
+ slash: {
135
+ name: 'hybrid-clear'
136
+ },
137
+ run: clear
138
+ }, {
139
+ id: 'hybrid-usage.restore',
140
+ title: 'Hybrid usage: restore totals for this project',
141
+ palette: true,
142
+ slash: {
143
+ name: 'hybrid-restore'
144
+ },
145
+ run: restore
146
+ }]
147
+ }));
148
+ return (() => {
149
+ var _el$3 = _$createElement("box"),
150
+ _el$4 = _$createElement("text");
151
+ _$insertNode(_el$3, _el$4);
152
+ _$setProp(_el$3, "flexDirection", "column");
153
+ _$setProp(_el$3, "gap", 1);
154
+ _$insertNode(_el$4, _$createTextNode(`[Hybrid Workflow settings]`));
155
+ _$setProp(_el$4, "onMouseDown", () => preferences.show());
156
+ _$insert(_el$3, _$createComponent(Show, {
157
+ get when() {
158
+ return error();
159
+ },
160
+ get children() {
161
+ var _el$6 = _$createElement("text");
162
+ _$insert(_el$6, error);
163
+ _$effect(_$p => _$setProp(_el$6, "fg", context.theme.text.muted, _$p));
164
+ return _el$6;
165
+ }
166
+ }), null);
167
+ _$insert(_el$3, _$createComponent(For, {
168
+ get each() {
169
+ return totals();
170
+ },
171
+ children: card => (() => {
172
+ var _el$11 = _$createElement("box"),
173
+ _el$12 = _$createElement("text"),
174
+ _el$13 = _$createElement("b"),
175
+ _el$14 = _$createTextNode(` · `),
176
+ _el$15 = _$createElement("text"),
177
+ _el$16 = _$createTextNode(` tokens · `),
178
+ _el$17 = _$createElement("text"),
179
+ _el$18 = _$createElement("text"),
180
+ _el$19 = _$createTextNode(`Input: `),
181
+ _el$20 = _$createElement("text"),
182
+ _el$21 = _$createTextNode(`Output: `),
183
+ _el$22 = _$createElement("text"),
184
+ _el$23 = _$createTextNode(`Cache: `);
185
+ _$insertNode(_el$11, _el$12);
186
+ _$insertNode(_el$11, _el$15);
187
+ _$insertNode(_el$11, _el$17);
188
+ _$insertNode(_el$11, _el$18);
189
+ _$insertNode(_el$11, _el$20);
190
+ _$insertNode(_el$11, _el$22);
191
+ _$setProp(_el$11, "flexDirection", "column");
192
+ _$insertNode(_el$12, _el$13);
193
+ _$insertNode(_el$13, _el$14);
194
+ _$insert(_el$13, () => card.model ?? settings.models[card.who], _el$14);
195
+ _$insert(_el$13, () => card.effort, null);
196
+ _$insertNode(_el$15, _el$16);
197
+ _$insert(_el$15, () => number(card.total), _el$16);
198
+ _$insert(_el$15, () => card.status, null);
199
+ _$insert(_el$17, () => money(card.cost));
200
+ _$insertNode(_el$18, _el$19);
201
+ _$insert(_el$18, () => number(card.input), null);
202
+ _$insertNode(_el$20, _el$21);
203
+ _$insert(_el$20, () => number(card.output), null);
204
+ _$insertNode(_el$22, _el$23);
205
+ _$insert(_el$22, () => number(card.cache), null);
206
+ _$insert(_el$11, _$createComponent(Show, {
207
+ get when() {
208
+ return card.partial;
209
+ },
210
+ get children() {
211
+ var _el$24 = _$createElement("text"),
212
+ _el$25 = _$createTextNode(`Partial · `),
213
+ _el$26 = _$createTextNode(`/`),
214
+ _el$27 = _$createTextNode(` measured`);
215
+ _$insertNode(_el$24, _el$25);
216
+ _$insertNode(_el$24, _el$26);
217
+ _$insertNode(_el$24, _el$27);
218
+ _$insert(_el$24, () => card.measuredCalls, _el$26);
219
+ _$insert(_el$24, () => card.calls, _el$27);
220
+ _$effect(_$p => _$setProp(_el$24, "fg", context.theme.text.muted, _$p));
221
+ return _el$24;
222
+ }
223
+ }), null);
224
+ _$effect(_p$ => {
225
+ var _v$ = context.theme.text.base,
226
+ _v$2 = context.theme.text.base,
227
+ _v$3 = context.theme.text.base,
228
+ _v$4 = context.theme.text.muted,
229
+ _v$5 = context.theme.text.muted,
230
+ _v$6 = context.theme.text.muted;
231
+ _v$ !== _p$.e && (_p$.e = _$setProp(_el$12, "fg", _v$, _p$.e));
232
+ _v$2 !== _p$.t && (_p$.t = _$setProp(_el$15, "fg", _v$2, _p$.t));
233
+ _v$3 !== _p$.a && (_p$.a = _$setProp(_el$17, "fg", _v$3, _p$.a));
234
+ _v$4 !== _p$.o && (_p$.o = _$setProp(_el$18, "fg", _v$4, _p$.o));
235
+ _v$5 !== _p$.i && (_p$.i = _$setProp(_el$20, "fg", _v$5, _p$.i));
236
+ _v$6 !== _p$.n && (_p$.n = _$setProp(_el$22, "fg", _v$6, _p$.n));
237
+ return _p$;
238
+ }, {
239
+ e: undefined,
240
+ t: undefined,
241
+ a: undefined,
242
+ o: undefined,
243
+ i: undefined,
244
+ n: undefined
245
+ });
246
+ return _el$11;
247
+ })()
248
+ }), null);
249
+ _$insert(_el$3, _$createComponent(Show, {
250
+ get when() {
251
+ return snapshot();
252
+ },
253
+ get children() {
254
+ return [(() => {
255
+ var _el$7 = _$createElement("text");
256
+ _$insert(_el$7, () => snapshot().task ? 'Project bridge usage · USD' : 'No bridge calls in this project');
257
+ _$effect(_$p => _$setProp(_el$7, "fg", context.theme.text.muted, _$p));
258
+ return _el$7;
259
+ })(), (() => {
260
+ var _el$8 = _$createElement("box"),
261
+ _el$9 = _$createElement("text");
262
+ _$insertNode(_el$8, _el$9);
263
+ _$setProp(_el$8, "flexDirection", "row");
264
+ _$setProp(_el$8, "gap", 2);
265
+ _$insertNode(_el$9, _$createTextNode(`[Clear totals]`));
266
+ _$setProp(_el$9, "onMouseDown", clear);
267
+ _$insert(_el$8, _$createComponent(Show, {
268
+ get when() {
269
+ return saved.resets[snapshot()?.key];
270
+ },
271
+ get children() {
272
+ var _el$1 = _$createElement("text");
273
+ _$insertNode(_el$1, _$createTextNode(`[Restore]`));
274
+ _$setProp(_el$1, "onMouseDown", restore);
275
+ _$effect(_$p => _$setProp(_el$1, "fg", context.theme.text.muted, _$p));
276
+ return _el$1;
277
+ }
278
+ }), null);
279
+ _$effect(_$p => _$setProp(_el$9, "fg", context.theme.text.muted, _$p));
280
+ return _el$8;
281
+ })()];
282
+ }
283
+ }), null);
284
+ _$effect(_$p => _$setProp(_el$4, "fg", context.theme.text.muted, _$p));
285
+ return _el$3;
286
+ })();
287
+ }
288
+ const sidebar = context.ui.slot({
289
+ append: 'sidebar.content',
290
+ render: props => _$createComponent(Usage, {
291
+ get sessionID() {
292
+ return props.sessionID;
293
+ }
294
+ })
295
+ });
296
+ return () => {
297
+ clearTimeout(firstRun);
298
+ preferences.dispose();
299
+ home?.();
300
+ sidebar?.();
301
+ };
302
+ }
303
+ });