@wolfx/opencode-magic-context 0.24.0 → 0.25.0
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/agents/magic-context-prompt.d.ts.map +1 -1
- package/dist/features/magic-context/compartment-chunk-embedding.d.ts +18 -0
- package/dist/features/magic-context/compartment-chunk-embedding.d.ts.map +1 -1
- package/dist/features/magic-context/memory/embedding-local.d.ts +4 -0
- package/dist/features/magic-context/memory/embedding-local.d.ts.map +1 -1
- package/dist/features/magic-context/memory/embedding-openai.d.ts +14 -0
- package/dist/features/magic-context/memory/embedding-openai.d.ts.map +1 -1
- package/dist/features/magic-context/memory/storage-memory-embeddings.d.ts +6 -0
- package/dist/features/magic-context/memory/storage-memory-embeddings.d.ts.map +1 -1
- package/dist/features/magic-context/project-embedding-registry.d.ts +38 -0
- package/dist/features/magic-context/project-embedding-registry.d.ts.map +1 -1
- package/dist/features/magic-context/storage-db.d.ts.map +1 -1
- package/dist/features/magic-context/storage-meta-session.d.ts +1 -0
- package/dist/features/magic-context/storage-meta-session.d.ts.map +1 -1
- package/dist/features/magic-context/storage-meta-shared.d.ts +2 -1
- package/dist/features/magic-context/storage-meta-shared.d.ts.map +1 -1
- package/dist/features/magic-context/storage-meta.d.ts +1 -1
- package/dist/features/magic-context/storage-meta.d.ts.map +1 -1
- package/dist/features/magic-context/storage-tags.d.ts +20 -1
- package/dist/features/magic-context/storage-tags.d.ts.map +1 -1
- package/dist/features/magic-context/storage.d.ts +2 -2
- package/dist/features/magic-context/storage.d.ts.map +1 -1
- package/dist/features/magic-context/types.d.ts +1 -0
- package/dist/features/magic-context/types.d.ts.map +1 -1
- package/dist/hooks/magic-context/apply-operations.d.ts +3 -2
- package/dist/hooks/magic-context/apply-operations.d.ts.map +1 -1
- package/dist/hooks/magic-context/caveman-cleanup.d.ts +1 -0
- package/dist/hooks/magic-context/caveman-cleanup.d.ts.map +1 -1
- package/dist/hooks/magic-context/channel2-delivery.d.ts +2 -0
- package/dist/hooks/magic-context/channel2-delivery.d.ts.map +1 -1
- package/dist/hooks/magic-context/command-handler.d.ts +7 -5
- package/dist/hooks/magic-context/command-handler.d.ts.map +1 -1
- package/dist/hooks/magic-context/ctx-reduce-nudge.d.ts +14 -4
- package/dist/hooks/magic-context/ctx-reduce-nudge.d.ts.map +1 -1
- package/dist/hooks/magic-context/embed-session-state.d.ts +14 -0
- package/dist/hooks/magic-context/embed-session-state.d.ts.map +1 -0
- package/dist/hooks/magic-context/event-handler.d.ts.map +1 -1
- package/dist/hooks/magic-context/format-embed-status.d.ts +9 -0
- package/dist/hooks/magic-context/format-embed-status.d.ts.map +1 -0
- package/dist/hooks/magic-context/heuristic-cleanup.d.ts +1 -0
- package/dist/hooks/magic-context/heuristic-cleanup.d.ts.map +1 -1
- package/dist/hooks/magic-context/hook-handlers.d.ts.map +1 -1
- package/dist/hooks/magic-context/hook.d.ts.map +1 -1
- package/dist/hooks/magic-context/inject-compartments.d.ts.map +1 -1
- package/dist/hooks/magic-context/protected-tail-boundary.d.ts.map +1 -1
- package/dist/hooks/magic-context/read-session-true-raw-tokens.d.ts +1 -1
- package/dist/hooks/magic-context/read-session-true-raw-tokens.d.ts.map +1 -1
- package/dist/hooks/magic-context/recomp-orchestrator.d.ts.map +1 -1
- package/dist/hooks/magic-context/strip-content.d.ts +0 -1
- package/dist/hooks/magic-context/strip-content.d.ts.map +1 -1
- package/dist/hooks/magic-context/tag-content-primitives.d.ts +2 -0
- package/dist/hooks/magic-context/tag-content-primitives.d.ts.map +1 -1
- package/dist/hooks/magic-context/tag-messages.d.ts.map +1 -1
- package/dist/hooks/magic-context/tool-drop-target.d.ts +1 -1
- package/dist/hooks/magic-context/tool-drop-target.d.ts.map +1 -1
- package/dist/hooks/magic-context/tool-reclaim.d.ts +12 -0
- package/dist/hooks/magic-context/tool-reclaim.d.ts.map +1 -0
- package/dist/hooks/magic-context/transform-operations.d.ts +1 -1
- package/dist/hooks/magic-context/transform-operations.d.ts.map +1 -1
- package/dist/hooks/magic-context/transform-postprocess-phase.d.ts.map +1 -1
- package/dist/hooks/magic-context/transform.d.ts +2 -0
- package/dist/hooks/magic-context/transform.d.ts.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1117 -378
- package/dist/plugin/conflict-warning-hook.d.ts.map +1 -1
- package/dist/plugin/hooks/create-session-hooks.d.ts.map +1 -1
- package/dist/plugin/rpc-handlers.d.ts.map +1 -1
- package/dist/shared/announcement.d.ts +1 -1
- package/dist/shared/model-suggestion-retry.d.ts.map +1 -1
- package/dist/shared/rpc-types.d.ts +20 -0
- package/dist/shared/rpc-types.d.ts.map +1 -1
- package/dist/shared/sqlite.d.ts +5 -1
- package/dist/shared/sqlite.d.ts.map +1 -1
- package/dist/shared/tui-preferences.d.ts +32 -0
- package/dist/shared/tui-preferences.d.ts.map +1 -0
- package/dist/tools/ctx-expand/constants.d.ts +1 -1
- package/dist/tools/ctx-expand/constants.d.ts.map +1 -1
- package/dist/tools/ctx-expand/render.d.ts +43 -0
- package/dist/tools/ctx-expand/render.d.ts.map +1 -0
- package/dist/tools/ctx-expand/tools.d.ts.map +1 -1
- package/dist/tools/ctx-expand/types.d.ts +6 -2
- package/dist/tools/ctx-expand/types.d.ts.map +1 -1
- package/dist/tools/ctx-reduce/constants.d.ts +1 -1
- package/dist/tools/ctx-reduce/constants.d.ts.map +1 -1
- package/dist/tui/data/context-db.d.ts +4 -2
- package/dist/tui/data/context-db.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/shared/announcement.ts +6 -6
- package/src/shared/model-suggestion-retry.test.ts +61 -1
- package/src/shared/model-suggestion-retry.ts +22 -0
- package/src/shared/rpc-types.ts +11 -0
- package/src/shared/sqlite-bind-style.test.ts +82 -0
- package/src/shared/sqlite.ts +30 -1
- package/src/shared/tag-transcript.test.ts +3 -1
- package/src/shared/tag-transcript.ts +19 -17
- package/src/shared/tui-preferences.test.ts +210 -0
- package/src/shared/tui-preferences.ts +303 -0
- package/src/tui/data/context-db.ts +34 -2
- package/src/tui/index.tsx +58 -4
- package/src/tui/slots/sidebar-content.tsx +102 -11
package/src/tui/index.tsx
CHANGED
|
@@ -6,7 +6,7 @@ import { createMemo } from "solid-js"
|
|
|
6
6
|
import type { TuiPlugin, TuiPluginApi, TuiThemeCurrent } from "@opencode-ai/plugin/tui"
|
|
7
7
|
import { createSidebarContentSlot, kickRecompProgressRefresh } from "./slots/sidebar-content"
|
|
8
8
|
import packageJson from "../../package.json"
|
|
9
|
-
import { closeRpc, consumeTuiMessages, dismissUpgradeReminder, getAnnouncement, getCompartmentCount, getRpcGeneration, initRpcClient, loadStatusDetail, markAnnounced, markTuiMessagesHandled, requestRecomp, requestUpgrade, type TuiMessage, type StatusDetail } from "./data/context-db"
|
|
9
|
+
import { closeRpc, consumeTuiMessages, dismissUpgradeReminder, getAnnouncement, getCompartmentCount, getRpcGeneration, initRpcClient, loadEmbedDetail, loadStatusDetail, markAnnounced, markTuiMessagesHandled, requestRecomp, requestUpgrade, type EmbedDetail, type TuiMessage, type StatusDetail } from "./data/context-db"
|
|
10
10
|
import { formatThresholdPercent } from "../shared/format-threshold"
|
|
11
11
|
import { detectConflicts } from "../shared/conflict-detector"
|
|
12
12
|
import { fixConflicts } from "../shared/conflict-fixer"
|
|
@@ -353,7 +353,7 @@ const StatusDialog = (props: { api: TuiPluginApi; s: StatusDetail }) => {
|
|
|
353
353
|
}
|
|
354
354
|
if (p.phase === "migration") return <R t={t()} l="Status" v={p.note ?? "Migrating memories ⟳"} fg={t().warning} />
|
|
355
355
|
if (p.phase === "done") return <R t={t()} l="Status" v={`✓ ${verb} complete`} fg={t().accent} />
|
|
356
|
-
if (p.phase === "skipped") return <R t={t()} l="Status" v={
|
|
356
|
+
if (p.phase === "skipped") return <R t={t()} l="Status" v={p.message ?? `${verb} stopped early`} fg={t().textMuted} />
|
|
357
357
|
return <R t={t()} l="Status" v={`✗ ${verb} failed${p.message ? `: ${p.message}` : ""}`} fg={t().error} />
|
|
358
358
|
})()}
|
|
359
359
|
</box>
|
|
@@ -580,14 +580,53 @@ async function showStatusDialog(api: TuiPluginApi, targetSessionId = getSessionI
|
|
|
580
580
|
const directory = api.state.path.directory ?? ""
|
|
581
581
|
const modelKey = getModelKeyFromMessages(api, sessionId)
|
|
582
582
|
const detail = await loadStatusDetail(sessionId, directory, modelKey)
|
|
583
|
-
// Ack only after the dialog is actually shown for the same active session;
|
|
584
|
-
// route switches while the RPC detail load is in flight must leave it pending.
|
|
585
583
|
if (getSessionId(api) !== sessionId) return false
|
|
586
584
|
|
|
587
585
|
api.ui.dialog.replace(() => <StatusDialog api={api} s={detail} />)
|
|
588
586
|
return true
|
|
589
587
|
}
|
|
590
588
|
|
|
589
|
+
const EmbedDialog = (props: { api: TuiPluginApi; detail: EmbedDetail }) => {
|
|
590
|
+
const theme = createMemo(() => (props.api as any).theme.current)
|
|
591
|
+
const t = () => theme()
|
|
592
|
+
const lines = () => props.detail.statusText.split("\n")
|
|
593
|
+
return (
|
|
594
|
+
<box flexDirection="column" width="100%" paddingLeft={2} paddingRight={2} paddingTop={1} paddingBottom={1}>
|
|
595
|
+
<box justifyContent="center" width="100%" marginBottom={1}>
|
|
596
|
+
<text fg={t().accent}><b>Embedding</b></text>
|
|
597
|
+
</box>
|
|
598
|
+
{lines().map((line) => (
|
|
599
|
+
<text fg={t().text}>{line}</text>
|
|
600
|
+
))}
|
|
601
|
+
</box>
|
|
602
|
+
)
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
async function showEmbedDialog(api: TuiPluginApi, targetSessionId = getSessionId(api)): Promise<boolean> {
|
|
606
|
+
const sessionId = targetSessionId
|
|
607
|
+
if (!sessionId) {
|
|
608
|
+
api.ui.toast({ message: "No active session", variant: "warning" })
|
|
609
|
+
return false
|
|
610
|
+
}
|
|
611
|
+
const directory = api.state.path.directory ?? ""
|
|
612
|
+
const detail = await loadEmbedDetail(sessionId, directory)
|
|
613
|
+
if (getSessionId(api) !== sessionId) return false
|
|
614
|
+
api.ui.dialog.replace(() => <EmbedDialog api={api} detail={detail} />)
|
|
615
|
+
return true
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
function showResultDialog(api: TuiPluginApi, title: string, message: string): boolean {
|
|
619
|
+
api.ui.dialog.replace(() => (
|
|
620
|
+
<api.ui.DialogAlert
|
|
621
|
+
title={title}
|
|
622
|
+
message={message}
|
|
623
|
+
onConfirm={() => {}}
|
|
624
|
+
/>
|
|
625
|
+
))
|
|
626
|
+
return true
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
|
|
591
630
|
/**
|
|
592
631
|
* Register Magic Context command palette entries, preferring the v1.14.42+
|
|
593
632
|
* `keymap.registerLayer` API and falling back to the legacy
|
|
@@ -842,6 +881,21 @@ const tui: TuiPlugin = async (api, _options, meta) => {
|
|
|
842
881
|
if (showUpgradeDialog(api, resume, requestedSessionId)) {
|
|
843
882
|
handledMessageIds.add(msg.id)
|
|
844
883
|
}
|
|
884
|
+
} else if (action === "show-embed-dialog") {
|
|
885
|
+
if (await showEmbedDialog(api, requestedSessionId)) {
|
|
886
|
+
handledMessageIds.add(msg.id)
|
|
887
|
+
}
|
|
888
|
+
} else if (action === "show-flush-dialog") {
|
|
889
|
+
const flushMsg = String(msg.payload?.message ?? "Flushed.")
|
|
890
|
+
if (showResultDialog(api, "Flush", flushMsg)) {
|
|
891
|
+
handledMessageIds.add(msg.id)
|
|
892
|
+
}
|
|
893
|
+
} else if (action === "show-result-dialog") {
|
|
894
|
+
const title = String(msg.payload?.title ?? "Magic Context")
|
|
895
|
+
const body = String(msg.payload?.message ?? "")
|
|
896
|
+
if (showResultDialog(api, title, body)) {
|
|
897
|
+
handledMessageIds.add(msg.id)
|
|
898
|
+
}
|
|
845
899
|
}
|
|
846
900
|
}
|
|
847
901
|
}
|
|
@@ -4,6 +4,15 @@ import type { TuiSlotPlugin, TuiPluginApi, TuiThemeCurrent } from "@opencode-ai/
|
|
|
4
4
|
import packageJson from "../../../package.json"
|
|
5
5
|
import { loadSidebarSnapshot, type SidebarSnapshot } from "../data/context-db"
|
|
6
6
|
import { formatThresholdPercent } from "../../shared/format-threshold"
|
|
7
|
+
import {
|
|
8
|
+
type MagicContextTuiPrefs,
|
|
9
|
+
PLUGIN_KEY,
|
|
10
|
+
queueTuiPreferenceUpdate,
|
|
11
|
+
readTuiPreferencesFile,
|
|
12
|
+
readTuiPreferencesFileSync,
|
|
13
|
+
resolveMagicContextPrefs,
|
|
14
|
+
watchTuiPreferences,
|
|
15
|
+
} from "../../shared/tui-preferences"
|
|
7
16
|
|
|
8
17
|
// Module-level hook so the upgrade/recomp dialog can kick the sidebar into its
|
|
9
18
|
// fast recomp self-poll the INSTANT the user confirms — without waiting for a
|
|
@@ -17,6 +26,64 @@ export function kickRecompProgressRefresh(): void {
|
|
|
17
26
|
const SINGLE_BORDER = { type: "single" } as any
|
|
18
27
|
const REFRESH_DEBOUNCE_MS = 150
|
|
19
28
|
|
|
29
|
+
export interface SidebarController {
|
|
30
|
+
prefs: () => MagicContextTuiPrefs
|
|
31
|
+
collapsed: () => boolean
|
|
32
|
+
toggleCollapsed: () => void
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// The TUI may unmount and remount sidebar_content when the user switches views
|
|
36
|
+
// (main -> subagent -> main). A remount re-runs the component body, so a signal
|
|
37
|
+
// created inside the component would reset to its seed. The controller lives in
|
|
38
|
+
// the slot-factory closure (plugin/process lifetime) and owns the durable
|
|
39
|
+
// prefs/collapse signals plus the single shared file watcher, so collapse state
|
|
40
|
+
// and live pref reloads survive remounts. No Solid effects/memos here — those
|
|
41
|
+
// need an owner; the poll-interval effect stays inside the component.
|
|
42
|
+
function createSidebarController(initialPrefs: MagicContextTuiPrefs): SidebarController {
|
|
43
|
+
const [prefs, setPrefs] = createSignal<MagicContextTuiPrefs>(initialPrefs)
|
|
44
|
+
const seedCollapsed =
|
|
45
|
+
initialPrefs.rememberCollapsed && initialPrefs.collapsed != null
|
|
46
|
+
? initialPrefs.collapsed
|
|
47
|
+
: initialPrefs.startCollapsed
|
|
48
|
+
const [collapsed, setCollapsed] = createSignal(seedCollapsed)
|
|
49
|
+
let lastPersistedCollapsed: boolean | null = initialPrefs.collapsed
|
|
50
|
+
let lastApplied = JSON.stringify(initialPrefs)
|
|
51
|
+
|
|
52
|
+
// Watcher lives for the process lifetime — intentionally never disposed.
|
|
53
|
+
// Collapse echo guard: lastPersistedCollapsed advances only once our own
|
|
54
|
+
// write lands, so a watcher echo of the value we just wrote is rejected by
|
|
55
|
+
// the `!==` check and cannot revert a user click.
|
|
56
|
+
watchTuiPreferences(() => {
|
|
57
|
+
void (async () => {
|
|
58
|
+
const next = resolveMagicContextPrefs(await readTuiPreferencesFile())
|
|
59
|
+
const serialized = JSON.stringify(next)
|
|
60
|
+
if (serialized === lastApplied) return
|
|
61
|
+
lastApplied = serialized
|
|
62
|
+
setPrefs(next)
|
|
63
|
+
if (
|
|
64
|
+
next.rememberCollapsed &&
|
|
65
|
+
next.collapsed != null &&
|
|
66
|
+
next.collapsed !== lastPersistedCollapsed
|
|
67
|
+
) {
|
|
68
|
+
lastPersistedCollapsed = next.collapsed
|
|
69
|
+
setCollapsed(next.collapsed)
|
|
70
|
+
}
|
|
71
|
+
})()
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
function toggleCollapsed() {
|
|
75
|
+
const next = !collapsed()
|
|
76
|
+
setCollapsed(next)
|
|
77
|
+
if (prefs().rememberCollapsed) {
|
|
78
|
+
void queueTuiPreferenceUpdate(PLUGIN_KEY, ["collapsed"], next).then(() => {
|
|
79
|
+
lastPersistedCollapsed = next
|
|
80
|
+
})
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return { prefs, collapsed, toggleCollapsed }
|
|
85
|
+
}
|
|
86
|
+
|
|
20
87
|
function compactTokens(value: number): string {
|
|
21
88
|
if (value >= 1_000_000) return `${(value / 1_000_000).toFixed(1)}M`
|
|
22
89
|
if (value >= 1_000) return `${(value / 1_000).toFixed(0)}K`
|
|
@@ -325,8 +392,13 @@ const RecompProgressSection = (props: {
|
|
|
325
392
|
case "done":
|
|
326
393
|
return { text: `✓ ${verb()} complete`, color: props.theme.success ?? props.theme.accent }
|
|
327
394
|
case "skipped":
|
|
328
|
-
//
|
|
329
|
-
|
|
395
|
+
// Neutral terse status next to the bold verb header; the full,
|
|
396
|
+
// self-contained reason (lease-busy "try again shortly" vs a
|
|
397
|
+
// partial-stall "run /ctx-embed start again") renders on its own
|
|
398
|
+
// line below. Don't re-prepend verb here (it's already the bold
|
|
399
|
+
// header — doing so read as "EmbedEmbed"), and don't hardcode
|
|
400
|
+
// "retry shortly" (wrong for a partial stall).
|
|
401
|
+
return { text: "stopped", color: props.theme.textMuted }
|
|
330
402
|
case "failed":
|
|
331
403
|
return { text: `✗ ${verb()} failed`, color: props.theme.error }
|
|
332
404
|
}
|
|
@@ -382,12 +454,15 @@ const SidebarContent = (props: {
|
|
|
382
454
|
api: TuiPluginApi
|
|
383
455
|
sessionID: () => string
|
|
384
456
|
theme: TuiThemeCurrent
|
|
457
|
+
controller: SidebarController
|
|
385
458
|
}) => {
|
|
386
459
|
const [snapshot, setSnapshot] = createSignal<SidebarSnapshot | null>(null)
|
|
387
|
-
//
|
|
388
|
-
//
|
|
389
|
-
//
|
|
390
|
-
const
|
|
460
|
+
// Collapse state + section visibility prefs live in the controller (plugin
|
|
461
|
+
// closure), so they survive view-switch remounts and persist across restarts
|
|
462
|
+
// via ~/.config/opencode/tui-preferences.jsonc. Read reactively.
|
|
463
|
+
const collapsed = props.controller.collapsed
|
|
464
|
+
const sections = () => props.controller.prefs().sections
|
|
465
|
+
const headerLabel = () => props.controller.prefs().header.label
|
|
391
466
|
let refreshTimer: ReturnType<typeof setTimeout> | undefined
|
|
392
467
|
// Self-sustaining poll while a recomp/upgrade is running. Recomp work
|
|
393
468
|
// happens in CHILD sessions whose message events are filtered out of the
|
|
@@ -610,11 +685,11 @@ const SidebarContent = (props: {
|
|
|
610
685
|
flexDirection="row"
|
|
611
686
|
justifyContent="space-between"
|
|
612
687
|
alignItems="center"
|
|
613
|
-
onMouseDown={() =>
|
|
688
|
+
onMouseDown={() => props.controller.toggleCollapsed()}
|
|
614
689
|
>
|
|
615
690
|
<box paddingLeft={1} paddingRight={1} backgroundColor={props.theme.accent}>
|
|
616
691
|
<text fg={props.theme.background}>
|
|
617
|
-
<b>{collapsed() ? "▶ " : "▼ "}
|
|
692
|
+
<b>{collapsed() ? "▶ " : "▼ "}{headerLabel()}</b>
|
|
618
693
|
</text>
|
|
619
694
|
</box>
|
|
620
695
|
<text fg={props.theme.textMuted}>v{packageJson.version}</text>
|
|
@@ -688,6 +763,8 @@ const SidebarContent = (props: {
|
|
|
688
763
|
{!collapsed() && (
|
|
689
764
|
<>
|
|
690
765
|
{/* Historian section */}
|
|
766
|
+
{sections().historian && (
|
|
767
|
+
<>
|
|
691
768
|
<box width="100%" marginTop={1} flexDirection="row" justifyContent="space-between">
|
|
692
769
|
<text fg={props.theme.text}>
|
|
693
770
|
<b>Historian</b>
|
|
@@ -713,8 +790,12 @@ const SidebarContent = (props: {
|
|
|
713
790
|
{s()?.recompProgress && (
|
|
714
791
|
<RecompProgressSection theme={props.theme} progress={s()!.recompProgress!} />
|
|
715
792
|
)}
|
|
793
|
+
</>
|
|
794
|
+
)}
|
|
716
795
|
|
|
717
796
|
{/* Memory section */}
|
|
797
|
+
{sections().memory && (
|
|
798
|
+
<>
|
|
718
799
|
<SectionHeader theme={props.theme} title="Memory" />
|
|
719
800
|
<StatRow
|
|
720
801
|
theme={props.theme}
|
|
@@ -730,9 +811,12 @@ const SidebarContent = (props: {
|
|
|
730
811
|
dim
|
|
731
812
|
/>
|
|
732
813
|
)}
|
|
814
|
+
</>
|
|
815
|
+
)}
|
|
733
816
|
|
|
734
817
|
{/* Queue & Status */}
|
|
735
|
-
{(
|
|
818
|
+
{sections().status &&
|
|
819
|
+
((s()?.pendingOpsCount ?? 0) > 0 ||
|
|
736
820
|
(s()?.sessionNoteCount ?? 0) > 0 ||
|
|
737
821
|
(s()?.readySmartNoteCount ?? 0) > 0) && (
|
|
738
822
|
<>
|
|
@@ -764,7 +848,7 @@ const SidebarContent = (props: {
|
|
|
764
848
|
)}
|
|
765
849
|
|
|
766
850
|
{/* Dreamer */}
|
|
767
|
-
{s()?.lastDreamerRunAt && (
|
|
851
|
+
{sections().dreamer && s()?.lastDreamerRunAt && (
|
|
768
852
|
<>
|
|
769
853
|
<SectionHeader theme={props.theme} title="Dreamer" />
|
|
770
854
|
<StatRow
|
|
@@ -782,7 +866,7 @@ const SidebarContent = (props: {
|
|
|
782
866
|
snapshot fields (newWorkTokens, totalInputTokens) and the
|
|
783
867
|
session_meta columns are still populated; only the UI is
|
|
784
868
|
simplified for now. */}
|
|
785
|
-
{s()?.totalInputTokens != null && (
|
|
869
|
+
{sections().stats && s()?.totalInputTokens != null && (
|
|
786
870
|
<>
|
|
787
871
|
<SectionHeader theme={props.theme} title="Stats" />
|
|
788
872
|
<StatRow
|
|
@@ -800,6 +884,12 @@ const SidebarContent = (props: {
|
|
|
800
884
|
}
|
|
801
885
|
|
|
802
886
|
export function createSidebarContentSlot(api: TuiPluginApi): TuiSlotPlugin {
|
|
887
|
+
// Seed synchronously at slot construction so the sidebar renders at its
|
|
888
|
+
// final collapse state + order on the first paint (no async flicker). The
|
|
889
|
+
// controller lives here in the factory closure for the plugin lifetime, so
|
|
890
|
+
// collapse state and live pref reloads survive sidebar_content remounts.
|
|
891
|
+
const seedRoot = readTuiPreferencesFileSync()
|
|
892
|
+
const controller = createSidebarController(resolveMagicContextPrefs(seedRoot))
|
|
803
893
|
return {
|
|
804
894
|
order: 153,
|
|
805
895
|
slots: {
|
|
@@ -810,6 +900,7 @@ export function createSidebarContentSlot(api: TuiPluginApi): TuiSlotPlugin {
|
|
|
810
900
|
api={api}
|
|
811
901
|
sessionID={() => value.session_id}
|
|
812
902
|
theme={theme()}
|
|
903
|
+
controller={controller}
|
|
813
904
|
/>
|
|
814
905
|
)
|
|
815
906
|
},
|