@fdcn/sourcefed 0.3.5 → 0.3.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/opencode.js CHANGED
@@ -7,7 +7,7 @@ import {
7
7
  daemonCommand,
8
8
  daemonEnvironment,
9
9
  spawnLocalDaemon
10
- } from "./chunk-X3BZSHKZ.js";
10
+ } from "./chunk-E6J3BAXP.js";
11
11
  import "./chunk-MLKGABMK.js";
12
12
 
13
13
  // packages/sourcefed/src/server.ts
@@ -22,9 +22,193 @@ import { Plugin } from "@opencode/plugin";
22
22
  import { existsSync } from "node:fs";
23
23
  import { fileURLToPath } from "node:url";
24
24
  import { Rpc } from "@opencode/plugin";
25
+
26
+ // adapters/opencode/subscriptions.ts
27
+ var REFRESH_MS = 15e3;
28
+ var OpenCodeSubscriptions = class {
29
+ constructor(connect) {
30
+ this.connect = connect;
31
+ }
32
+ owners = /* @__PURE__ */ new Set();
33
+ subscriptions = /* @__PURE__ */ new Map();
34
+ lifetime = new AbortController();
35
+ daemon;
36
+ connecting;
37
+ refreshing;
38
+ dirty = false;
39
+ lastAttemptAt = -Infinity;
40
+ timer;
41
+ get closed() {
42
+ return this.lifetime.signal.aborted;
43
+ }
44
+ async add(owner) {
45
+ if (this.closed) throw new Error("sourcefed subscription hub is closed");
46
+ this.owners.add(owner);
47
+ if (!this.timer) {
48
+ this.timer = setInterval(() => void this.refresh(), REFRESH_MS);
49
+ this.timer.unref?.();
50
+ }
51
+ await this.refresh();
52
+ }
53
+ async remove(owner) {
54
+ this.owners.delete(owner);
55
+ const closing = [];
56
+ for (const [id, subscription] of this.subscriptions) {
57
+ if (this.ownerFor(subscription.info)) continue;
58
+ this.subscriptions.delete(id);
59
+ closing.push(this.closeSubscription(subscription));
60
+ }
61
+ if (this.owners.size > 0) {
62
+ await Promise.all(closing);
63
+ await this.refresh();
64
+ return;
65
+ }
66
+ this.lifetime.abort();
67
+ clearInterval(this.timer);
68
+ this.timer = void 0;
69
+ await Promise.all(closing);
70
+ await this.daemon?.close();
71
+ this.daemon = void 0;
72
+ await this.connecting;
73
+ await this.refreshing;
74
+ }
75
+ async request(method, params) {
76
+ const daemon = await this.ensureDaemon();
77
+ if (!daemon || this.closed) throw new Error("sourcefed daemon unavailable or bridge closed");
78
+ return daemon.request(method, params);
79
+ }
80
+ refresh() {
81
+ if (this.closed) return Promise.resolve();
82
+ this.dirty = true;
83
+ if (!this.refreshing) {
84
+ this.refreshing = this.refreshLoop();
85
+ }
86
+ return this.refreshing;
87
+ }
88
+ async refreshLoop() {
89
+ try {
90
+ do {
91
+ this.dirty = false;
92
+ try {
93
+ const daemon = await this.ensureDaemon();
94
+ if (daemon && !this.closed) await this.reconcile(daemon);
95
+ } catch (error) {
96
+ if (!this.closed) console.error(`[sourcefed] refresh failed: ${String(error)}`);
97
+ }
98
+ } while (this.dirty && !this.closed);
99
+ } finally {
100
+ this.refreshing = void 0;
101
+ }
102
+ }
103
+ async ensureDaemon() {
104
+ if (this.closed) return void 0;
105
+ if (this.daemon) return this.daemon;
106
+ if (this.connecting) return this.connecting;
107
+ if (Date.now() - this.lastAttemptAt < REFRESH_MS) return void 0;
108
+ this.lastAttemptAt = Date.now();
109
+ this.connecting = this.connect().then(async (daemon) => {
110
+ if (this.closed) {
111
+ await daemon.close();
112
+ return void 0;
113
+ }
114
+ this.daemon = daemon;
115
+ return daemon;
116
+ }).catch((error) => {
117
+ console.error(`[sourcefed] daemon unavailable: ${String(error)}`);
118
+ return void 0;
119
+ }).finally(() => {
120
+ this.connecting = void 0;
121
+ });
122
+ return this.connecting;
123
+ }
124
+ async reconcile(daemon) {
125
+ const result = await daemon.request("monitor.targets", { kind: "opencode-session" });
126
+ const targets = enabledSessions(result);
127
+ for (const [id, subscription] of this.subscriptions) {
128
+ if (targets.has(id)) continue;
129
+ this.subscriptions.delete(id);
130
+ await this.closeSubscription(subscription);
131
+ }
132
+ for (const id of targets) {
133
+ if (this.closed) return;
134
+ const reader = this.owners.values().next().value;
135
+ if (!reader) return;
136
+ let info;
137
+ try {
138
+ info = await reader.getSession(id, this.lifetime.signal);
139
+ } catch (error) {
140
+ if (!error || typeof error !== "object" || !("_tag" in error) || error._tag !== "SessionNotFoundError") {
141
+ if (!this.closed) console.error(`[sourcefed] session ${id} lookup failed: ${String(error)}`);
142
+ continue;
143
+ }
144
+ }
145
+ if (this.closed) return;
146
+ const owner = info && this.ownerFor(info);
147
+ const existing = this.subscriptions.get(id);
148
+ if (!owner || !info) {
149
+ if (existing) {
150
+ this.subscriptions.delete(id);
151
+ await this.closeSubscription(existing);
152
+ }
153
+ } else if (existing) {
154
+ existing.info = info;
155
+ } else {
156
+ await this.subscribe(daemon, id, info);
157
+ }
158
+ }
159
+ }
160
+ ownerFor(info) {
161
+ const candidates = [...this.owners].filter((owner) => owner.location.project.id === info.projectID);
162
+ return candidates.find((owner) => owner.location.directory === info.location.directory) ?? candidates[0];
163
+ }
164
+ async subscribe(daemon, id, info) {
165
+ const controller = new AbortController();
166
+ const subscription = {
167
+ info,
168
+ controller,
169
+ listener: daemon.subscribe({ kind: "opencode-session", id }, async (events) => {
170
+ await this.route(id, subscription, events);
171
+ }, { signal: controller.signal })
172
+ };
173
+ this.subscriptions.set(id, subscription);
174
+ try {
175
+ await subscription.listener;
176
+ } catch (error) {
177
+ if (this.subscriptions.get(id) === subscription) this.subscriptions.delete(id);
178
+ if (!controller.signal.aborted) console.error(`[sourcefed] subscribe ${id} failed: ${String(error)}`);
179
+ }
180
+ }
181
+ async route(id, subscription, events) {
182
+ const reader = this.owners.values().next().value;
183
+ if (!reader) throw new Error("sourcefed session owner unloaded");
184
+ const info = await reader.getSession(id, this.lifetime.signal);
185
+ const owner = this.ownerFor(info);
186
+ if (!owner) throw new Error("sourcefed session has no loaded project owner");
187
+ subscription.info = info;
188
+ await owner.routeEvents(events);
189
+ }
190
+ async closeSubscription(subscription) {
191
+ subscription.controller.abort();
192
+ await subscription.listener.then((listener) => listener.close(), () => void 0);
193
+ }
194
+ };
195
+ function enabledSessions(result) {
196
+ if (!result || typeof result !== "object" || !("targets" in result) || !Array.isArray(result.targets)) {
197
+ throw new Error("invalid monitor.targets response");
198
+ }
199
+ const ids = /* @__PURE__ */ new Set();
200
+ for (const target of result.targets) {
201
+ if (!target || target.kind !== "opencode-session" || typeof target.id !== "string") {
202
+ throw new Error("invalid opencode-session target");
203
+ }
204
+ ids.add(target.id);
205
+ }
206
+ return ids;
207
+ }
208
+
209
+ // adapters/opencode/bridge.ts
25
210
  var TARGET_KIND = "opencode-session";
26
211
  var GATE_TIMEOUT_MS = 3e3;
27
- var RESUBSCRIBE_MS = 15e3;
28
212
  var ChauffeurGate = Rpc.define({
29
213
  id: "chauffeur",
30
214
  methods: {
@@ -52,97 +236,53 @@ var ChauffeurGate = Rpc.define({
52
236
  },
53
237
  events: {}
54
238
  });
55
- var activeBridge;
239
+ var HUB = Symbol.for("sourcefed.opencode.subscriptions.v1");
240
+ var shared = globalThis;
241
+ function subscriptions() {
242
+ if (!shared[HUB] || shared[HUB].closed) shared[HUB] = new OpenCodeSubscriptions(connectDaemon);
243
+ return shared[HUB];
244
+ }
56
245
  var OpenCodeBridge = class {
57
- constructor(session, rpc) {
246
+ constructor(session, rpc, location, hub = subscriptions()) {
58
247
  this.session = session;
59
248
  this.rpc = rpc;
249
+ this.location = location;
250
+ this.hub = hub;
60
251
  }
61
- daemon;
62
- listeners = /* @__PURE__ */ new Map();
63
- lastAttemptAt = 0;
64
- lastError;
65
- timer;
252
+ started;
253
+ closed = false;
254
+ closing;
66
255
  /**
67
256
  * Chauffeur or the CLI can create a monitor for a session here at any time,
68
257
  * without this bridge's tools, so check for new targets periodically too.
69
258
  */
70
259
  async start() {
71
- await this.ensureDaemon();
72
- this.timer = setInterval(() => void this.refresh(), RESUBSCRIBE_MS);
73
- this.timer.unref?.();
260
+ if (this.closed) throw new Error("sourcefed bridge is closed");
261
+ this.started ??= this.hub.add(this);
262
+ await this.started;
74
263
  }
75
- async ensureTarget(sessionID) {
76
- await this.ensureDaemon();
77
- const existing = this.listeners.get(sessionID);
78
- if (existing) {
79
- await existing;
80
- return;
81
- }
82
- const pending = this.daemon.subscribe(this.target(sessionID), async (events) => {
83
- await this.routeEvents(events);
84
- });
85
- this.listeners.set(sessionID, pending);
264
+ async callTool(name, arguments_, sessionID) {
86
265
  try {
87
- await pending;
266
+ await this.start();
267
+ const method = name.replace(/_/g, ".");
268
+ const result = await this.hub.request(method, { ...arguments_, target: this.target(sessionID) });
269
+ if (["monitor.create", "monitor.start", "monitor.stop", "monitor.remove"].includes(method)) await this.hub.refresh();
270
+ return result;
88
271
  } catch (error) {
89
- this.listeners.delete(sessionID);
90
- throw error;
91
- }
92
- }
93
- async callTool(name, arguments_, sessionID) {
94
- await this.ensureDaemon();
95
- if (!this.daemon) {
96
- return { ok: false, error: `sourcefed daemon unavailable: ${this.lastError ?? "not started"}` };
272
+ return { ok: false, error: String(error) };
97
273
  }
98
- await this.ensureTarget(sessionID);
99
- return this.daemon.request(name.replace(/_/g, "."), { ...arguments_, target: this.target(sessionID) });
100
274
  }
101
- async close() {
102
- clearInterval(this.timer);
103
- this.timer = void 0;
104
- for (const pending of this.listeners.values()) await pending.then((listener) => listener.close(), () => void 0);
105
- this.listeners.clear();
106
- await this.daemon?.close();
107
- this.daemon = void 0;
275
+ close() {
276
+ if (this.closing) return this.closing;
277
+ this.closed = true;
278
+ this.closing = this.started ? this.hub.remove(this) : Promise.resolve();
279
+ return this.closing;
108
280
  }
109
281
  async refresh() {
110
- if (!this.daemon) return this.ensureDaemon();
111
- await this.resubscribe();
282
+ if (!this.closed) await this.hub.refresh();
112
283
  }
113
- async ensureDaemon() {
114
- if (this.daemon) return;
115
- if (Date.now() - this.lastAttemptAt < 15e3) return;
116
- this.lastAttemptAt = Date.now();
117
- try {
118
- this.daemon = await connectDaemon();
119
- void this.resubscribe();
120
- } catch (error) {
121
- this.lastError = error instanceof Error ? error.message : String(error);
122
- console.error(`[sourcefed] daemon unavailable: ${this.lastError}`);
123
- }
124
- }
125
- /**
126
- * Monitors outlive this process, so after a restart nothing listens for their
127
- * sessions until something subscribes. Subscribe every session that has an
128
- * enabled monitor and still exists here; a deleted session is skipped, since
129
- * delivering to it would fail and retry forever.
130
- */
131
- async resubscribe() {
132
- try {
133
- const { targets } = await this.daemon.request("monitor.targets", { kind: TARGET_KIND });
134
- await Promise.all(targets.map((target) => this.resubscribeTarget(target.id)));
135
- } catch (error) {
136
- console.error(`[sourcefed] resubscribe failed: ${error instanceof Error ? error.message : String(error)}`);
137
- }
138
- }
139
- async resubscribeTarget(sessionID) {
140
- if (this.listeners.has(sessionID)) return;
141
- const exists = await this.session.get({ sessionID }).then(() => true, () => false);
142
- if (!exists) return;
143
- await this.ensureTarget(sessionID).catch((error) => {
144
- console.error(`[sourcefed] subscribe ${sessionID} failed: ${error instanceof Error ? error.message : String(error)}`);
145
- });
284
+ getSession(sessionID, signal) {
285
+ return this.session.get({ sessionID }, { signal: AbortSignal.any([signal, AbortSignal.timeout(3e3)]) });
146
286
  }
147
287
  // Every event arrives as a synthetic message, never as a user prompt, so it is
148
288
  // not mistaken for the user's own words. Actionable events resume an idle
@@ -182,7 +322,7 @@ var OpenCodeBridge = class {
182
322
  },
183
323
  { signal: AbortSignal.timeout(GATE_TIMEOUT_MS) }
184
324
  );
185
- return reply.deliver !== false;
325
+ return !(reply && typeof reply === "object" && "deliver" in reply && reply.deliver === false);
186
326
  } catch {
187
327
  return true;
188
328
  }
@@ -207,22 +347,15 @@ function cliEntry() {
207
347
  if (existsSync(bundled)) return bundled;
208
348
  return fileURLToPath(import.meta.resolve("@sourcefed/cli"));
209
349
  }
210
- function setOpenCodeBridge(bridge) {
211
- activeBridge = bridge;
212
- }
213
- function getOpenCodeBridge() {
214
- if (!activeBridge) throw new Error("Sourcefed OpenCode bridge is not initialized");
215
- return activeBridge;
216
- }
217
350
 
218
351
  // adapters/opencode/tool-result.ts
219
- async function callMonitorTool(name, arguments_, sessionID) {
220
- const result = await getOpenCodeBridge().callTool(name, arguments_, sessionID);
352
+ async function callMonitorTool(bridge, name, arguments_, sessionID) {
353
+ const result = await bridge.callTool(name, arguments_, sessionID);
221
354
  return JSON.stringify(result);
222
355
  }
223
356
 
224
357
  // adapters/opencode/tools/monitor_create.ts
225
- var definition = {
358
+ var monitor_create_default = (bridge) => ({
226
359
  name: "monitor_create",
227
360
  description: "Create a detect-only monitor that watches a Jira issue, GitHub PR, Slack thread, or Slack DM and routes NEW events into the current session. Slack monitors only read and notify; they never reply. GitHub and Slack use webhooks when configured and polling otherwise; Jira uses polling.",
228
361
  input: {
@@ -242,13 +375,12 @@ var definition = {
242
375
  additionalProperties: false
243
376
  },
244
377
  async execute(input, context) {
245
- return { content: await callMonitorTool("monitor_create", input ?? {}, context.sessionID) };
378
+ return { content: await callMonitorTool(bridge, "monitor_create", input ?? {}, context.sessionID) };
246
379
  }
247
- };
248
- var monitor_create_default = definition;
380
+ });
249
381
 
250
382
  // adapters/opencode/tools/monitor_list.ts
251
- var definition2 = {
383
+ var monitor_list_default = (bridge) => ({
252
384
  name: "monitor_list",
253
385
  description: "List monitors created by the current session (id, name, source, delivery, enabled).",
254
386
  input: {
@@ -257,13 +389,12 @@ var definition2 = {
257
389
  additionalProperties: false
258
390
  },
259
391
  async execute(_input, context) {
260
- return { content: await callMonitorTool("monitor_list", {}, context.sessionID) };
392
+ return { content: await callMonitorTool(bridge, "monitor_list", {}, context.sessionID) };
261
393
  }
262
- };
263
- var monitor_list_default = definition2;
394
+ });
264
395
 
265
396
  // adapters/opencode/tools/monitor_status.ts
266
- var definition3 = {
397
+ var monitor_status_default = (bridge) => ({
267
398
  name: "monitor_status",
268
399
  description: "Get the status of a monitor created by the current session.",
269
400
  input: {
@@ -276,13 +407,12 @@ var definition3 = {
276
407
  },
277
408
  async execute(input, context) {
278
409
  const args = input ?? {};
279
- return { content: await callMonitorTool("monitor_status", { id: args.id }, context.sessionID) };
410
+ return { content: await callMonitorTool(bridge, "monitor_status", { id: args.id }, context.sessionID) };
280
411
  }
281
- };
282
- var monitor_status_default = definition3;
412
+ });
283
413
 
284
414
  // adapters/opencode/tools/monitor_start.ts
285
- var definition4 = {
415
+ var monitor_start_default = (bridge) => ({
286
416
  name: "monitor_start",
287
417
  description: "Start (re-enable) a stopped monitor created by the current session.",
288
418
  input: {
@@ -295,13 +425,12 @@ var definition4 = {
295
425
  },
296
426
  async execute(input, context) {
297
427
  const args = input ?? {};
298
- return { content: await callMonitorTool("monitor_start", { id: args.id }, context.sessionID) };
428
+ return { content: await callMonitorTool(bridge, "monitor_start", { id: args.id }, context.sessionID) };
299
429
  }
300
- };
301
- var monitor_start_default = definition4;
430
+ });
302
431
 
303
432
  // adapters/opencode/tools/monitor_stop.ts
304
- var definition5 = {
433
+ var monitor_stop_default = (bridge) => ({
305
434
  name: "monitor_stop",
306
435
  description: "Stop a monitor created by the current session.",
307
436
  input: {
@@ -314,23 +443,26 @@ var definition5 = {
314
443
  },
315
444
  async execute(input, context) {
316
445
  const args = input ?? {};
317
- return { content: await callMonitorTool("monitor_stop", { id: args.id }, context.sessionID) };
446
+ return { content: await callMonitorTool(bridge, "monitor_stop", { id: args.id }, context.sessionID) };
318
447
  }
319
- };
320
- var monitor_stop_default = definition5;
448
+ });
321
449
 
322
450
  // adapters/opencode/index.ts
323
451
  async function setupSourcefed(ctx) {
324
- const bridge = new OpenCodeBridge(ctx.session, ctx.rpc);
325
- setOpenCodeBridge(bridge);
326
- await bridge.start();
327
- await ctx.tool.transform((editor) => {
328
- editor.add(monitor_create_default);
329
- editor.add(monitor_list_default);
330
- editor.add(monitor_status_default);
331
- editor.add(monitor_start_default);
332
- editor.add(monitor_stop_default);
333
- });
452
+ const bridge = new OpenCodeBridge(ctx.session, ctx.rpc, ctx.location);
453
+ try {
454
+ await bridge.start();
455
+ await ctx.tool.transform((editor) => {
456
+ editor.add(monitor_create_default(bridge));
457
+ editor.add(monitor_list_default(bridge));
458
+ editor.add(monitor_status_default(bridge));
459
+ editor.add(monitor_start_default(bridge));
460
+ editor.add(monitor_stop_default(bridge));
461
+ });
462
+ } catch (error) {
463
+ await bridge.close();
464
+ throw error;
465
+ }
334
466
  return () => bridge.close();
335
467
  }
336
468
  var opencode_default = Plugin.define({
@@ -345,11 +477,16 @@ var server_default = Plugin2.define({
345
477
  id: "sourcefed",
346
478
  async setup(ctx) {
347
479
  const cleanup = await setupSourcefed(ctx);
348
- await ctx.session.hook("context", (event) => {
349
- if (!event.system.some((part) => part.type === "text" && part.text.includes(heading))) {
350
- event.system.push({ type: "text", text: guidance });
351
- }
352
- });
480
+ try {
481
+ await ctx.session.hook("context", (event) => {
482
+ if (!event.system.some((part) => part.type === "text" && part.text.includes(heading))) {
483
+ event.system.push({ type: "text", text: guidance });
484
+ }
485
+ });
486
+ } catch (error) {
487
+ await cleanup?.();
488
+ throw error;
489
+ }
353
490
  return cleanup;
354
491
  }
355
492
  });
package/dist/pi.js CHANGED
@@ -6,7 +6,7 @@ import {
6
6
  daemonCommand,
7
7
  daemonEnvironment,
8
8
  spawnLocalDaemon
9
- } from "./chunk-X3BZSHKZ.js";
9
+ } from "./chunk-E6J3BAXP.js";
10
10
  import "./chunk-MLKGABMK.js";
11
11
 
12
12
  // adapters/pi/src/index.ts
@@ -59,38 +59,43 @@ function Sidebar(props) {
59
59
  void refresh();
60
60
  const timer = setInterval(() => void refresh(), REFRESH_MS);
61
61
  onCleanup(() => clearInterval(timer));
62
- return (() => {
63
- var _el$ = _$createElement("box"), _el$2 = _$createElement("box"), _el$3 = _$createElement("text"), _el$5 = _$createElement("text"), _el$6 = _$createTextNode(` (`), _el$7 = _$createTextNode(`)`);
64
- _$insertNode(_el$, _el$2);
65
- _$setProp(_el$, "flexDirection", "column");
66
- _$setProp(_el$, "width", "100%");
67
- _$setProp(_el$, "marginTop", 1);
68
- _$insertNode(_el$2, _el$3);
69
- _$insertNode(_el$2, _el$5);
70
- _$setProp(_el$2, "flexDirection", "row");
71
- _$setProp(_el$2, "width", "100%");
72
- _$insertNode(_el$3, _$createTextNode(`Sourcefed`));
73
- _$insertNode(_el$5, _el$6);
74
- _$insertNode(_el$5, _el$7);
75
- _$insert(_el$5, () => active().length, _el$7);
76
- _$insert(_el$, _$createComponent(MonitorRows, {
77
- monitors: active,
78
- get tone() {
79
- return palette();
80
- },
81
- compact: true
82
- }), null);
83
- _$effect((_p$) => {
84
- var _v$ = palette().accent, _v$2 = palette().textMuted;
85
- _v$ !== _p$.e && (_p$.e = _$setProp(_el$3, "fg", _v$, _p$.e));
86
- _v$2 !== _p$.t && (_p$.t = _$setProp(_el$5, "fg", _v$2, _p$.t));
87
- return _p$;
88
- }, {
89
- e: void 0,
90
- t: void 0
91
- });
92
- return _el$;
93
- })();
62
+ return _$createComponent(Show, {
63
+ get when() {
64
+ return active().length > 0;
65
+ },
66
+ get children() {
67
+ var _el$ = _$createElement("box"), _el$2 = _$createElement("box"), _el$3 = _$createElement("text"), _el$5 = _$createElement("text"), _el$6 = _$createTextNode(` (`), _el$7 = _$createTextNode(`)`);
68
+ _$insertNode(_el$, _el$2);
69
+ _$setProp(_el$, "flexDirection", "column");
70
+ _$setProp(_el$, "width", "100%");
71
+ _$setProp(_el$, "marginTop", 1);
72
+ _$insertNode(_el$2, _el$3);
73
+ _$insertNode(_el$2, _el$5);
74
+ _$setProp(_el$2, "flexDirection", "row");
75
+ _$setProp(_el$2, "width", "100%");
76
+ _$insertNode(_el$3, _$createTextNode(`Sourcefed`));
77
+ _$insertNode(_el$5, _el$6);
78
+ _$insertNode(_el$5, _el$7);
79
+ _$insert(_el$5, () => active().length, _el$7);
80
+ _$insert(_el$, _$createComponent(MonitorRows, {
81
+ monitors: active,
82
+ get tone() {
83
+ return palette();
84
+ },
85
+ compact: true
86
+ }), null);
87
+ _$effect((_p$) => {
88
+ var _v$ = palette().accent, _v$2 = palette().textMuted;
89
+ _v$ !== _p$.e && (_p$.e = _$setProp(_el$3, "fg", _v$, _p$.e));
90
+ _v$2 !== _p$.t && (_p$.t = _$setProp(_el$5, "fg", _v$2, _p$.t));
91
+ return _p$;
92
+ }, {
93
+ e: void 0,
94
+ t: void 0
95
+ });
96
+ return _el$;
97
+ }
98
+ });
94
99
  }
95
100
  function MonitorRows(props) {
96
101
  const visible = createMemo(() => props.monitors().slice(0, 4));
@@ -98,41 +103,26 @@ function MonitorRows(props) {
98
103
  var _el$8 = _$createElement("box");
99
104
  _$setProp(_el$8, "flexDirection", "column");
100
105
  _$setProp(_el$8, "width", "100%");
101
- _$insert(_el$8, _$createComponent(Show, {
102
- get when() {
103
- return visible().length > 0;
104
- },
105
- get fallback() {
106
- return (() => {
107
- var _el$1 = _$createElement("text");
108
- _$insertNode(_el$1, _$createTextNode(`No active monitors`));
109
- _$effect((_$p) => _$setProp(_el$1, "fg", props.tone.textMuted, _$p));
110
- return _el$1;
111
- })();
112
- },
113
- get children() {
114
- return visible().map((monitor) => (() => {
115
- var _el$11 = _$createElement("box"), _el$12 = _$createElement("text"), _el$13 = _$createElement("text"), _el$14 = _$createTextNode(` `);
116
- _$insertNode(_el$11, _el$12);
117
- _$insertNode(_el$11, _el$13);
118
- _$setProp(_el$11, "flexDirection", "row");
119
- _$setProp(_el$11, "width", "100%");
120
- _$insert(_el$12, () => monitor.icon);
121
- _$insertNode(_el$13, _el$14);
122
- _$insert(_el$13, () => monitor.name, null);
123
- _$effect((_p$) => {
124
- var _v$3 = monitorTone(monitor, props.tone), _v$4 = props.tone.textMuted;
125
- _v$3 !== _p$.e && (_p$.e = _$setProp(_el$12, "fg", _v$3, _p$.e));
126
- _v$4 !== _p$.t && (_p$.t = _$setProp(_el$13, "fg", _v$4, _p$.t));
127
- return _p$;
128
- }, {
129
- e: void 0,
130
- t: void 0
131
- });
132
- return _el$11;
133
- })());
134
- }
135
- }), null);
106
+ _$insert(_el$8, () => visible().map((monitor) => (() => {
107
+ var _el$1 = _$createElement("box"), _el$10 = _$createElement("text"), _el$11 = _$createElement("text"), _el$12 = _$createTextNode(` `);
108
+ _$insertNode(_el$1, _el$10);
109
+ _$insertNode(_el$1, _el$11);
110
+ _$setProp(_el$1, "flexDirection", "row");
111
+ _$setProp(_el$1, "width", "100%");
112
+ _$insert(_el$10, () => monitor.icon);
113
+ _$insertNode(_el$11, _el$12);
114
+ _$insert(_el$11, () => monitor.name, null);
115
+ _$effect((_p$) => {
116
+ var _v$3 = monitorTone(monitor, props.tone), _v$4 = props.tone.textMuted;
117
+ _v$3 !== _p$.e && (_p$.e = _$setProp(_el$10, "fg", _v$3, _p$.e));
118
+ _v$4 !== _p$.t && (_p$.t = _$setProp(_el$11, "fg", _v$4, _p$.t));
119
+ return _p$;
120
+ }, {
121
+ e: void 0,
122
+ t: void 0
123
+ });
124
+ return _el$1;
125
+ })()), null);
136
126
  _$insert(_el$8, _$createComponent(Show, {
137
127
  get when() {
138
128
  return _$memo(() => !!props.compact)() && visible().length < props.monitors().length;