@op1/threads 0.1.7 → 0.1.8

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/tui.ts CHANGED
@@ -1,7 +1,17 @@
1
1
  import { Plugin } from "@opencode/plugin/tui";
2
- import { createEffect } from "solid-js";
2
+ import { getComponentCatalogue } from "@opentui/solid/components";
3
+ import { createEffect, createSignal } from "solid-js";
3
4
  import { z } from "zod";
4
5
  import { ThreadsRpc } from "./src/rpc";
6
+ import { activity } from "./src/activity";
7
+ import { cleanRoleTitle } from "./src/activity-model";
8
+ import {
9
+ BoxRenderable,
10
+ ScrollBoxRenderable,
11
+ TextRenderable,
12
+ TextAttributes,
13
+ RGBA,
14
+ } from "@opentui/core";
5
15
 
6
16
  const CoordinatorRef = z.object({ coordinatorID: z.string() });
7
17
 
@@ -9,15 +19,26 @@ export default Plugin.define({
9
19
  id: "op-threads",
10
20
  setup(ctx) {
11
21
  const rpc = ctx.client.rpc(ThreadsRpc);
22
+ const sidebar = activity(
23
+ ctx,
24
+ { BoxRenderable, ScrollBoxRenderable, TextRenderable, TextAttributes, RGBA },
25
+ { createEffect, createSignal },
26
+ getComponentCatalogue().spinner,
27
+ );
28
+ const [cleaned, saveCleaned] = ctx.storage.store("role-title-cleanup", {
29
+ initial: { ids: [] as string[] },
30
+ });
12
31
  const initial: { workerIDs: string[] } = { workerIDs: [] };
13
32
  const [seen, updateSeen] = ctx.storage.memory("seen-workers", { initial });
14
33
  const closing = new Set<string>();
34
+ const abort = new AbortController();
15
35
  let stopped = false;
16
36
  let running = false;
17
37
  let reopenPending = false;
18
38
  let lastError: string | undefined;
19
39
  let movingFrom: string | undefined;
20
40
  function groupTabs() {
41
+ if (sidebar.mounted()) return;
21
42
  const tabs = ctx.ui.tabs.list().map((tab) => {
22
43
  const projectID = ctx.data.session.get(tab.sessionID)?.projectID;
23
44
  return {
@@ -80,11 +101,20 @@ export default Plugin.define({
80
101
  if (!coordinatorIDs.length) return;
81
102
  const { workers } = await (reopen ? rpc.restore : rpc.snapshot)(
82
103
  { coordinatorIDs },
83
- { location: ctx.location ?? ctx.data.location.default() },
104
+ {
105
+ location: ctx.location ?? ctx.data.location.default(),
106
+ signal: abort.signal,
107
+ },
84
108
  );
109
+ if (reopen)
110
+ await sidebar.restore(workers.map((worker) => worker.workerID));
111
+ sidebar.updateWorkers(workers);
85
112
  for (const worker of workers) {
86
113
  if (stopped) return;
87
- const tab = ctx.ui.tabs.list().find((tab) => tab.sessionID === worker.workerID);
114
+ if (!reopen && sidebar.isDismissed(worker.workerID)) continue;
115
+ const tab = ctx.ui.tabs
116
+ .list()
117
+ .find((tab) => tab.sessionID === worker.workerID);
88
118
  if (closing.has(worker.workerID) && tab) continue;
89
119
  const closed = closing.delete(worker.workerID);
90
120
  if (
@@ -107,7 +137,8 @@ export default Plugin.define({
107
137
  }
108
138
  continue;
109
139
  }
110
- if (!reopen && !closed && seen.workerIDs.includes(worker.workerID)) continue;
140
+ if (!reopen && !closed && seen.workerIDs.includes(worker.workerID))
141
+ continue;
111
142
  await ctx.data.session.sync(worker.workerID);
112
143
  if (
113
144
  !stopped &&
@@ -129,10 +160,24 @@ export default Plugin.define({
129
160
  if (stopped) return;
130
161
  const role = roles.get(tab.sessionID);
131
162
  const session = ctx.data.session.get(tab.sessionID);
132
- if (!role || !session?.title) continue;
133
- const title = `[${role}] ${session.title.replace(/^\[(?:Main|Worker)\] /, "")}`;
134
- if (title === session.title) continue;
135
- await ctx.client.session.update({ sessionID: tab.sessionID, title });
163
+ if (!role || !session || cleaned.ids.includes(tab.sessionID))
164
+ continue;
165
+ const fresh = await ctx.client.session.get(
166
+ { sessionID: tab.sessionID },
167
+ { signal: abort.signal },
168
+ );
169
+ if (stopped) return;
170
+ const title = cleanRoleTitle(fresh.title ?? "", true);
171
+ if (title && title !== fresh.title)
172
+ await ctx.client.session.update(
173
+ { sessionID: tab.sessionID, title },
174
+ { signal: abort.signal },
175
+ );
176
+ if (stopped) return;
177
+ await saveCleaned((draft) => {
178
+ if (!draft.ids.includes(tab.sessionID))
179
+ draft.ids.push(tab.sessionID);
180
+ });
136
181
  }
137
182
  groupTabs();
138
183
  }
@@ -182,6 +227,8 @@ export default Plugin.define({
182
227
  refresh();
183
228
  return () => {
184
229
  stopped = true;
230
+ abort.abort();
231
+ sidebar.dispose();
185
232
  clearInterval(timer);
186
233
  stopEvents();
187
234
  removeSlot();