@mingxy/cerebro 1.5.10 → 1.6.1

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/package.json CHANGED
@@ -1,11 +1,12 @@
1
1
  {
2
2
  "name": "@mingxy/cerebro",
3
- "version": "1.5.10",
3
+ "version": "1.6.1",
4
4
  "description": "Cerebro persistent memory plugin for OpenCode — auto-recall, auto-capture, 9 memory tools with clustering",
5
5
  "type": "module",
6
6
  "main": "src/index.ts",
7
7
  "oc-plugin": [
8
- "server"
8
+ "server",
9
+ "tui"
9
10
  ],
10
11
  "keywords": [
11
12
  "opencode",
package/src/client.ts CHANGED
@@ -359,4 +359,16 @@ export class OmemClient {
359
359
  );
360
360
  return res?.recalls ?? [];
361
361
  }
362
+
363
+ async sessionIngest(
364
+ messages: Array<{ role: string; content: string }>,
365
+ sessionId?: string,
366
+ agentId?: string,
367
+ ): Promise<unknown> {
368
+ return this.post("/v1/memories/session-ingest", {
369
+ messages,
370
+ session_id: sessionId,
371
+ agent_id: agentId,
372
+ }, 60000);
373
+ }
362
374
  }
package/src/hooks.ts CHANGED
@@ -12,31 +12,17 @@ function showToast(tui: any, title: string, message: string, variant: string = "
12
12
  }, delayMs);
13
13
  }
14
14
 
15
+ function extractUserRequest(content: string): string {
16
+ const match = content.match(/<user-request>([\s\S]*?)<\/user-request>/);
17
+ return match ? match[1].trim() : content;
18
+ }
19
+
15
20
  const keywordDetectedSessions = new Set<string>();
16
21
  const injectedMemoryIds = new Map<string, Set<string>>();
17
22
  const firstMessages = new Map<string, string>();
18
23
  const sessionMessages = new Map<string, Array<{ role: string; content: string }>>();
19
24
  const profileInjectedSessions = new Set<string>();
20
25
 
21
- function extractMemoryIds(result: unknown): string[] {
22
- if (!result) return [];
23
- if (Array.isArray(result)) {
24
- return (result as Array<{ id?: string }>).map((m) => m.id).filter(Boolean) as string[];
25
- }
26
- if (typeof result === "object" && result !== null) {
27
- const r = result as Record<string, unknown>;
28
- if (Array.isArray(r.memories)) {
29
- return (r.memories as Array<{ id?: string }>).map((m) => m.id).filter(Boolean) as string[];
30
- }
31
- if (Array.isArray(r.results)) {
32
- return (r.results as Array<{ id?: string; memory?: { id?: string } }>)
33
- .map((m) => m.id ?? m.memory?.id)
34
- .filter(Boolean) as string[];
35
- }
36
- }
37
- return [];
38
- }
39
-
40
26
  function formatRelativeAge(isoDate: string): string {
41
27
  const diffMs = Date.now() - new Date(isoDate).getTime();
42
28
  const minutes = Math.floor(diffMs / 60_000);
@@ -149,14 +135,15 @@ export function autoRecallHook(client: OmemClient, containerTags: string[], tui:
149
135
  try {
150
136
  const messages = sessionMessages.get(input.sessionID) ?? [];
151
137
  const userMessages = messages.filter((m) => m.role === "user");
152
- const query_text = userMessages[userMessages.length - 1]?.content || firstMessages.get(input.sessionID) || "";
138
+ const rawQuery = userMessages[userMessages.length - 1]?.content || firstMessages.get(input.sessionID) || "";
139
+ const query_text = extractUserRequest(rawQuery);
153
140
  const last_query_text = userMessages.length >= 2 ? userMessages[userMessages.length - 2].content : undefined;
154
141
 
155
142
  const projectTags = containerTags.filter(t => t.startsWith("omem_project_"));
156
143
  const shouldRecallRes = await client.shouldRecall(query_text, last_query_text, input.sessionID, similarityThreshold, maxRecallResults, projectTags.length > 0 ? projectTags : undefined);
157
144
 
158
145
  if (!shouldRecallRes) {
159
- showToast(tui, "🧠 Omem Service Unavailable", "Unable to reach memory API · check connection", "error", toastDelayMs);
146
+ showToast(tui, "🧠 Cerebro Service Unavailable", "Unable to reach memory API · check connection", "error", toastDelayMs);
160
147
  return;
161
148
  }
162
149
 
@@ -263,14 +250,14 @@ export function autoRecallHook(client: OmemClient, containerTags: string[], tui:
263
250
  // Server returned error (500, etc.) with details
264
251
  const cleanMsg = errMsg.replace(/^\[omem\]\s*/, "");
265
252
  if (cleanMsg.startsWith("500")) {
266
- showToast(tui, "🧠 Omem Server Error", cleanMsg.substring(0, 200), "error");
253
+ showToast(tui, "🧠 Cerebro Server Error", cleanMsg.substring(0, 200), "error");
267
254
  } else if (cleanMsg.includes("timed out")) {
268
- showToast(tui, "🧠 Omem Service Timeout", cleanMsg.substring(0, 100), "error");
255
+ showToast(tui, "🧠 Cerebro Service Timeout", cleanMsg.substring(0, 100), "error");
269
256
  } else {
270
- showToast(tui, "🧠 Omem Error", cleanMsg.substring(0, 150), "error");
257
+ showToast(tui, "🧠 Cerebro Error", cleanMsg.substring(0, 150), "error");
271
258
  }
272
259
  } else if (errMsg.includes("fetch") || errMsg.includes("network")) {
273
- showToast(tui, "🧠 Omem Service Unavailable", "Network error · check API connection", "error");
260
+ showToast(tui, "🧠 Cerebro Service Unavailable", "Network error · check API connection", "error");
274
261
  } else {
275
262
  showToast(tui, "🧠 Memory Recall Error", errMsg.substring(0, 100), "error");
276
263
  }
@@ -278,7 +265,7 @@ export function autoRecallHook(client: OmemClient, containerTags: string[], tui:
278
265
  };
279
266
  }
280
267
 
281
- export function keywordDetectionHook(client: OmemClient, containerTags: string[], threshold: number, tui: any, ingestMode: "smart" | "raw" = "smart") {
268
+ export function keywordDetectionHook(_client: OmemClient, _containerTags: string[], threshold: number, _tui: any, _ingestMode: "smart" | "raw" = "smart") {
282
269
  return async (
283
270
  input: { sessionID: string; messageID?: string },
284
271
  output: { message: UserMessage; parts: Part[] },
@@ -307,65 +294,41 @@ export function keywordDetectionHook(client: OmemClient, containerTags: string[]
307
294
  });
308
295
 
309
296
  const messages = sessionMessages.get(input.sessionID)!;
297
+ // Ingest is now handled by sessionIdleHook (session.idle → sessionIngest API).
298
+ // This hook only collects messages and detects keywords for recall.
310
299
  if (messages.length >= threshold) {
311
- try {
312
- const result = await client.ingestMessages(messages, {
313
- mode: ingestMode,
314
- tags: [...containerTags, "auto-capture"],
315
- sessionId: input.sessionID,
316
- });
317
- if (result === null) {
318
- showToast(tui, "🔴 Capture Failed", `Memory capture blocked · check API Key and spiritual connection`, "error");
319
- } else {
320
- showToast(tui, "🧠 Memory Sealed", `${messages.length} dialogues captured · entrusted to the heavens for refinement`, "success");
321
- const memoryIds = extractMemoryIds(result);
322
- if (memoryIds.length > 0) {
323
- const recordResult = await client.recordSessionRecall(
324
- input.sessionID,
325
- memoryIds,
326
- "auto",
327
- firstMessages.get(input.sessionID) || "",
328
- 0,
329
- 0,
330
- );
331
- if (recordResult) {
332
- showToast(tui, "📦 Capture Recorded", `${memoryIds.length} memory(s) saved to session history`, "success");
333
- } else {
334
- showToast(tui, "🔴 Capture Record Failed", `Failed to save capture record · check API connection`, "error");
335
- }
336
- }
337
- sessionMessages.delete(input.sessionID);
338
- }
339
- } catch {
340
- showToast(tui, "🔴 Capture Failed", "Memory capture blocked · spiritual pulse anomaly", "error");
341
- }
300
+ // Threshold reached — messages will be processed on next session.idle
342
301
  }
343
302
  };
344
303
  }
345
304
 
346
- export function compactingHook(client: OmemClient, containerTags: string[], tui: any, ingestMode: "smart" | "raw" = "smart") {
305
+ export function compactingHook(client: OmemClient, containerTags: string[], tui: any, ingestMode: "smart" | "raw" = "smart", isAutoStoreEnabled?: (sessionId: string | undefined) => boolean) {
347
306
  return async (
348
307
  input: { sessionID?: string },
349
308
  output: { context: string[]; prompt?: string },
350
309
  ) => {
351
310
  if (input.sessionID && sessionMessages.has(input.sessionID)) {
352
- const messages = sessionMessages.get(input.sessionID)!;
353
- if (messages.length > 0) {
354
- try {
355
- const result = await client.ingestMessages(messages, {
356
- mode: ingestMode,
357
- tags: [...containerTags, "auto-capture"],
358
- sessionId: input.sessionID,
359
- });
360
- if (result === null) {
361
- showToast(tui, "🔴 Archive Failed", "Session archive blocked · check spiritual realm status", "error");
362
- } else {
363
- showToast(tui, "📦 Session Archived", `${messages.length} residual dialogues archived · merged into the realm`, "success");
311
+ if (isAutoStoreEnabled && !isAutoStoreEnabled(input.sessionID)) {
312
+ sessionMessages.delete(input.sessionID);
313
+ } else {
314
+ const messages = sessionMessages.get(input.sessionID)!;
315
+ if (messages.length > 0) {
316
+ try {
317
+ const result = await client.ingestMessages(messages, {
318
+ mode: ingestMode,
319
+ tags: [...containerTags, "auto-capture"],
320
+ sessionId: input.sessionID,
321
+ });
322
+ if (result === null) {
323
+ showToast(tui, "🔴 Archive Failed", "Session archive blocked · check spiritual realm status", "error");
324
+ } else {
325
+ showToast(tui, "📦 Session Archived", `${messages.length} residual dialogues archived · merged into the realm`, "success");
326
+ }
327
+ } catch {
328
+ showToast(tui, "🔴 Archive Failed", "Session archive blocked · spiritual pulse anomaly", "error");
364
329
  }
365
- } catch {
366
- showToast(tui, "🔴 Archive Failed", "Session archive blocked · spiritual pulse anomaly", "error");
330
+ sessionMessages.delete(input.sessionID);
367
331
  }
368
- sessionMessages.delete(input.sessionID);
369
332
  }
370
333
  }
371
334
 
@@ -379,3 +342,97 @@ export function compactingHook(client: OmemClient, containerTags: string[], tui:
379
342
  }
380
343
  };
381
344
  }
345
+
346
+ const processedMessageIds = new Set<string>();
347
+ const pluginStartTime = Date.now();
348
+
349
+ export function sessionIdleHook(
350
+ omemClient: OmemClient,
351
+ _containerTags: string[],
352
+ tui: any,
353
+ sdkClient: any,
354
+ _ingestMode: "smart" | "raw" = "smart",
355
+ threshold: number = 0,
356
+ getMainSessionId?: () => string | undefined,
357
+ isAutoStoreEnabled?: (sessionId: string | undefined) => boolean,
358
+ ) {
359
+ let idleTimeout: ReturnType<typeof setTimeout> | null = null;
360
+ let isCapturing = false;
361
+
362
+ return async (input: { event: { type: string; properties?: any } }) => {
363
+ if (input.event.type !== "session.idle") return;
364
+
365
+ const sessionID = input.event.properties?.sessionID;
366
+ if (!sessionID) return;
367
+
368
+ if (isAutoStoreEnabled && !isAutoStoreEnabled(sessionID)) return;
369
+
370
+ if (getMainSessionId) {
371
+ const mainId = getMainSessionId();
372
+ if (mainId && sessionID !== mainId) return;
373
+ }
374
+
375
+ if (idleTimeout) clearTimeout(idleTimeout);
376
+
377
+ idleTimeout = setTimeout(async () => {
378
+ if (isCapturing) return;
379
+ isCapturing = true;
380
+
381
+ try {
382
+ const response = await sdkClient.session.messages({ path: { id: sessionID } });
383
+ if (!response?.data) return;
384
+
385
+ const messages = response.data;
386
+ const conversationMessages: Array<{ role: string; content: string }> = [];
387
+ const newMessageIds: string[] = [];
388
+ let hasNewMessages = false;
389
+
390
+ for (const msg of messages) {
391
+ const msgId = msg.info?.id;
392
+ if (!msgId || processedMessageIds.has(msgId)) continue;
393
+
394
+ // Skip messages created before this plugin instance started
395
+ // (prevents replaying entire session history on restart)
396
+ const msgTime = msg.info?.createdAt ? new Date(msg.info.createdAt).getTime() : 0;
397
+ if (msgTime > 0 && msgTime < pluginStartTime) continue;
398
+
399
+ const role = msg.info?.role;
400
+ if (role !== "user" && role !== "assistant") continue;
401
+
402
+ const textParts = (msg.parts || [])
403
+ .filter((p: any) => p.type === "text" && p.text)
404
+ .map((p: any) => p.text);
405
+ const text = textParts.join("\n").trim();
406
+ if (!text) continue;
407
+
408
+ hasNewMessages = true;
409
+ newMessageIds.push(msgId);
410
+ conversationMessages.push({ role, content: text });
411
+ }
412
+
413
+ if (!hasNewMessages || conversationMessages.length === 0) return;
414
+
415
+ if (threshold > 1 && conversationMessages.length < threshold) {
416
+ // Log that we're waiting for more messages
417
+ return;
418
+ }
419
+
420
+ try {
421
+ await omemClient.sessionIngest(conversationMessages, sessionID);
422
+ for (const id of newMessageIds) {
423
+ processedMessageIds.add(id);
424
+ }
425
+ showToast(tui, "🧠 Memory Sealed", `${conversationMessages.length} dialogues captured · entrusted to the heavens for refinement`, "success");
426
+ } catch (err) {
427
+ showToast(tui, "🔴 Session Capture Failed", String(err).substring(0, 100), "error");
428
+ }
429
+ } catch (err) {
430
+ const errMsg = err instanceof Error ? err.message : String(err);
431
+ showToast(tui, "🔴 Idle Capture Error", errMsg.substring(0, 100), "error");
432
+ } finally {
433
+ isCapturing = false;
434
+ idleTimeout = null;
435
+ }
436
+ }, 10000);
437
+ };
438
+ }
package/src/index.ts CHANGED
@@ -3,7 +3,7 @@ import { readFileSync } from "node:fs";
3
3
  import { join, dirname } from "node:path";
4
4
  import { fileURLToPath } from "node:url";
5
5
  import { OmemClient } from "./client.js";
6
- import { autoRecallHook, compactingHook, keywordDetectionHook } from "./hooks.js";
6
+ import { autoRecallHook, compactingHook, keywordDetectionHook, sessionIdleHook } from "./hooks.js";
7
7
  import { getUserTag, getProjectTag } from "./tags.js";
8
8
  import { buildTools } from "./tools.js";
9
9
  import { logInfo, logError } from "./logger.js";
@@ -20,7 +20,22 @@ try {
20
20
  }
21
21
  } catch {}
22
22
 
23
- function showToast(tui: any, title: string, message: string, variant: string = "info", duration: number = 5000) {
23
+ // Per-session auto-store toggle: sessionId enabled (default: true = auto-store on)
24
+ const autoStoreSessions = new Map<string, boolean>();
25
+
26
+ export function isAutoStoreEnabled(sessionId: string | undefined): boolean {
27
+ if (!sessionId) return true;
28
+ return autoStoreSessions.get(sessionId) ?? true;
29
+ }
30
+
31
+ export function setAutoStoreEnabled(sessionId: string, enabled: boolean): void {
32
+ autoStoreSessions.set(sessionId, enabled);
33
+ }
34
+
35
+ // Bridge for TUI plugin (same process, different module graph)
36
+ (globalThis as any).__cerebro_autoStore = isAutoStoreEnabled;
37
+
38
+ function showToast(tui: any, title: string, message?: string, variant: string = "info", duration: number = 5000) {
24
39
  if (!tui) return;
25
40
  setTimeout(() => {
26
41
  try {
@@ -48,13 +63,7 @@ const OmemPlugin: Plugin = async (input) => {
48
63
  // 启动时检测连接状态
49
64
  try {
50
65
  await omemClient.getStats();
51
- showToast(
52
- tui,
53
- `🧠 Omem v${pluginVersion} · Connected`,
54
- `${config.apiUrl.replace(/^https?:\/\//, "")}`,
55
- "success",
56
- 6000
57
- );
66
+ showToast(tui, `🧠 Cerebro v${pluginVersion} · Connected`, undefined, "success", 6000);
58
67
  logInfo(`Connected to ${config.apiUrl}`);
59
68
  } catch (err) {
60
69
  const errMsg = err instanceof Error ? err.message : String(err);
@@ -63,7 +72,7 @@ const OmemPlugin: Plugin = async (input) => {
63
72
  const cleanMsg = errMsg.replace(/^\[omem\]\s*/, "");
64
73
  showToast(
65
74
  tui,
66
- `🧠 Omem v${pluginVersion} · Server Error`,
75
+ `🧠 Cerebro v${pluginVersion} · Server Error`,
67
76
  cleanMsg.substring(0, 150),
68
77
  "error",
69
78
  8000
@@ -71,7 +80,7 @@ const OmemPlugin: Plugin = async (input) => {
71
80
  } else {
72
81
  showToast(
73
82
  tui,
74
- `🧠 Omem v${pluginVersion} · Connection Failed`,
83
+ `🧠 Cerebro v${pluginVersion} · Connection Failed`,
75
84
  `Unable to reach ${config.apiUrl}`,
76
85
  "error",
77
86
  8000
@@ -89,13 +98,36 @@ const OmemPlugin: Plugin = async (input) => {
89
98
  const recallHook = autoRecallHook(omemClient, containerTags, tui, config);
90
99
 
91
100
  return {
101
+ config: async (cfg: any) => {
102
+ cfg.command ??= {};
103
+ cfg.command["memory-toggle"] = {
104
+ template: "/memory-toggle <on|off>",
105
+ description: "Toggle Cerebro auto-store ON or OFF for current session",
106
+ };
107
+ },
108
+ "command.execute.before": async (input: { command: string; sessionID: string; arguments: string }, output: { parts: any[] }) => {
109
+ if (input.command !== "memory-toggle") return;
110
+ const arg = input.arguments.trim().toLowerCase();
111
+ const sessionId = input.sessionID;
112
+ if (arg === "off") {
113
+ setAutoStoreEnabled(sessionId, false);
114
+ output.parts = [{ type: "text", text: "⏸️ Cerebro auto-store: OFF — manual memory_store still works" }];
115
+ } else if (arg === "on") {
116
+ setAutoStoreEnabled(sessionId, true);
117
+ output.parts = [{ type: "text", text: "✅ Cerebro auto-store: ON" }];
118
+ } else {
119
+ const current = isAutoStoreEnabled(sessionId);
120
+ output.parts = [{ type: "text", text: `Cerebro auto-store: ${current ? "✅ ON" : "⏸️ OFF"}\nUsage: /memory-toggle on | off` }];
121
+ }
122
+ },
92
123
  "experimental.chat.system.transform": async (input: any, output: any) => {
93
124
  if (input.sessionID) currentSessionId = input.sessionID;
94
125
  return recallHook(input, output);
95
126
  },
96
127
  "chat.message": keywordDetectionHook(omemClient, containerTags, config.autoCaptureThreshold, tui, config.ingestMode),
97
- "experimental.session.compacting": compactingHook(omemClient, containerTags, tui, config.ingestMode),
128
+ "experimental.session.compacting": compactingHook(omemClient, containerTags, tui, config.ingestMode, isAutoStoreEnabled),
98
129
  tool: buildTools(omemClient, containerTags, { agentId, getSessionId: () => currentSessionId }),
130
+ event: sessionIdleHook(omemClient, containerTags, tui, client, config.ingestMode, config.autoCaptureThreshold, () => currentSessionId, isAutoStoreEnabled),
99
131
  "shell.env": async (_input: any, output: any) => {
100
132
  if (directory) {
101
133
  output.env.OMEM_PROJECT_DIR = directory;
package/src/tools.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import { tool } from "@opencode-ai/plugin";
2
2
  import type { OmemClient } from "./client.js";
3
+ import { isAutoStoreEnabled, setAutoStoreEnabled } from "./index.js";
3
4
 
4
5
  function extractMemoryIds(result: unknown): string[] {
5
6
  if (!result) return [];
@@ -373,5 +374,31 @@ export function buildTools(client: OmemClient, containerTags: string[], context:
373
374
  return JSON.stringify({ ok: true, result });
374
375
  },
375
376
  }),
377
+
378
+ memory_toggle: tool({
379
+ description:
380
+ "Toggle Cerebro auto-store ON or OFF for current session. Does NOT affect manual memory_store calls.",
381
+ args: {
382
+ state: tool.schema
383
+ .string()
384
+ .optional()
385
+ .describe("Set to 'on' or 'off'. Omit to check current status."),
386
+ },
387
+ async execute(args) {
388
+ const sessionId = context.getSessionId();
389
+ if (!sessionId) return JSON.stringify({ ok: false, error: "No active session" });
390
+
391
+ if (args.state === "on") {
392
+ setAutoStoreEnabled(sessionId, true);
393
+ return JSON.stringify({ ok: true, auto_store: true, message: "Cerebro auto-store: ON" });
394
+ } else if (args.state === "off") {
395
+ setAutoStoreEnabled(sessionId, false);
396
+ return JSON.stringify({ ok: true, auto_store: false, message: "Cerebro auto-store: OFF" });
397
+ } else {
398
+ const current = isAutoStoreEnabled(sessionId);
399
+ return JSON.stringify({ ok: true, auto_store: current, message: `Cerebro auto-store: ${current ? "ON" : "OFF"}` });
400
+ }
401
+ },
402
+ }),
376
403
  };
377
404
  }
package/src/tui.tsx ADDED
@@ -0,0 +1,72 @@
1
+ // @ts-nocheck — TUI JSX is resolved at runtime by opencode (same as quota plugin)
2
+ /** @jsxImportSource @opentui/solid */
3
+ import type { TuiPlugin, TuiPluginApi, TuiPluginModule } from "@opencode-ai/plugin/tui";
4
+ import { createEffect, createSignal, onCleanup } from "solid-js";
5
+
6
+ const id = "@mingxy/cerebro";
7
+ const SIDEBAR_ORDER = 160;
8
+
9
+ function SidebarContentView(props: {
10
+ api: TuiPluginApi;
11
+ sessionID: string;
12
+ }) {
13
+ const [autoStore, setAutoStore] = createSignal(true);
14
+
15
+ const unsubscribers = [
16
+ props.api.event.on("session.updated", () => {
17
+ setAutoStore(globalThis.__cerebro_autoStore?.(props.sessionID) ?? true);
18
+ }),
19
+ props.api.event.on("tui.session.select", (event) => {
20
+ if (event.properties?.sessionID === props.sessionID) {
21
+ setAutoStore(globalThis.__cerebro_autoStore?.(props.sessionID) ?? true);
22
+ }
23
+ }),
24
+ ];
25
+
26
+ createEffect(() => {
27
+ props.sessionID;
28
+ setAutoStore(globalThis.__cerebro_autoStore?.(props.sessionID) ?? true);
29
+ });
30
+
31
+ const interval = setInterval(() => {
32
+ setAutoStore(globalThis.__cerebro_autoStore?.(props.sessionID) ?? true);
33
+ }, 2000);
34
+
35
+ onCleanup(() => {
36
+ clearInterval(interval);
37
+ for (const unsubscribe of unsubscribers) unsubscribe();
38
+ });
39
+
40
+ const enabled = autoStore();
41
+
42
+ return (
43
+ <box gap={0}>
44
+ <text fg={props.api.theme.current.text}>
45
+ <b>Cerebro</b>
46
+ </text>
47
+ <box gap={0}>
48
+ <text fg={props.api.theme.current.text} wrapMode="none">
49
+ {enabled ? "✅ Auto-store: ON" : "⏸️ Auto-store: OFF"}
50
+ </text>
51
+ </box>
52
+ </box>
53
+ );
54
+ }
55
+
56
+ const tui: TuiPlugin = async (api) => {
57
+ api.slots.register({
58
+ order: SIDEBAR_ORDER,
59
+ slots: {
60
+ sidebar_content(_ctx, props: { session_id: string }) {
61
+ return <SidebarContentView api={api} sessionID={props.session_id} />;
62
+ },
63
+ },
64
+ });
65
+ };
66
+
67
+ const pluginModule: TuiPluginModule & { id: string } = {
68
+ id,
69
+ tui,
70
+ };
71
+
72
+ export default pluginModule;
package/tsconfig.json CHANGED
@@ -19,6 +19,6 @@
19
19
  "isolatedModules": true,
20
20
  "types": ["node"]
21
21
  },
22
- "include": ["src/**/*.ts"],
22
+ "include": ["src/**/*.ts", "src/**/*.tsx"],
23
23
  "exclude": ["node_modules", "dist"]
24
24
  }