@cortexkit/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/README.md +4 -2
- 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 +106 -12
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,17 @@ 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
|
+
computeEffectiveOrder,
|
|
9
|
+
DEFAULT_SLOT_ORDER,
|
|
10
|
+
type MagicContextTuiPrefs,
|
|
11
|
+
PLUGIN_KEY,
|
|
12
|
+
queueTuiPreferenceUpdate,
|
|
13
|
+
readTuiPreferencesFile,
|
|
14
|
+
readTuiPreferencesFileSync,
|
|
15
|
+
resolveMagicContextPrefs,
|
|
16
|
+
watchTuiPreferences,
|
|
17
|
+
} from "../../shared/tui-preferences"
|
|
7
18
|
|
|
8
19
|
// Module-level hook so the upgrade/recomp dialog can kick the sidebar into its
|
|
9
20
|
// fast recomp self-poll the INSTANT the user confirms — without waiting for a
|
|
@@ -17,6 +28,64 @@ export function kickRecompProgressRefresh(): void {
|
|
|
17
28
|
const SINGLE_BORDER = { type: "single" } as any
|
|
18
29
|
const REFRESH_DEBOUNCE_MS = 150
|
|
19
30
|
|
|
31
|
+
export interface SidebarController {
|
|
32
|
+
prefs: () => MagicContextTuiPrefs
|
|
33
|
+
collapsed: () => boolean
|
|
34
|
+
toggleCollapsed: () => void
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// The TUI may unmount and remount sidebar_content when the user switches views
|
|
38
|
+
// (main -> subagent -> main). A remount re-runs the component body, so a signal
|
|
39
|
+
// created inside the component would reset to its seed. The controller lives in
|
|
40
|
+
// the slot-factory closure (plugin/process lifetime) and owns the durable
|
|
41
|
+
// prefs/collapse signals plus the single shared file watcher, so collapse state
|
|
42
|
+
// and live pref reloads survive remounts. No Solid effects/memos here — those
|
|
43
|
+
// need an owner; the poll-interval effect stays inside the component.
|
|
44
|
+
function createSidebarController(initialPrefs: MagicContextTuiPrefs): SidebarController {
|
|
45
|
+
const [prefs, setPrefs] = createSignal<MagicContextTuiPrefs>(initialPrefs)
|
|
46
|
+
const seedCollapsed =
|
|
47
|
+
initialPrefs.rememberCollapsed && initialPrefs.collapsed != null
|
|
48
|
+
? initialPrefs.collapsed
|
|
49
|
+
: initialPrefs.startCollapsed
|
|
50
|
+
const [collapsed, setCollapsed] = createSignal(seedCollapsed)
|
|
51
|
+
let lastPersistedCollapsed: boolean | null = initialPrefs.collapsed
|
|
52
|
+
let lastApplied = JSON.stringify(initialPrefs)
|
|
53
|
+
|
|
54
|
+
// Watcher lives for the process lifetime — intentionally never disposed.
|
|
55
|
+
// Collapse echo guard: lastPersistedCollapsed advances only once our own
|
|
56
|
+
// write lands, so a watcher echo of the value we just wrote is rejected by
|
|
57
|
+
// the `!==` check and cannot revert a user click.
|
|
58
|
+
watchTuiPreferences(() => {
|
|
59
|
+
void (async () => {
|
|
60
|
+
const next = resolveMagicContextPrefs(await readTuiPreferencesFile())
|
|
61
|
+
const serialized = JSON.stringify(next)
|
|
62
|
+
if (serialized === lastApplied) return
|
|
63
|
+
lastApplied = serialized
|
|
64
|
+
setPrefs(next)
|
|
65
|
+
if (
|
|
66
|
+
next.rememberCollapsed &&
|
|
67
|
+
next.collapsed != null &&
|
|
68
|
+
next.collapsed !== lastPersistedCollapsed
|
|
69
|
+
) {
|
|
70
|
+
lastPersistedCollapsed = next.collapsed
|
|
71
|
+
setCollapsed(next.collapsed)
|
|
72
|
+
}
|
|
73
|
+
})()
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
function toggleCollapsed() {
|
|
77
|
+
const next = !collapsed()
|
|
78
|
+
setCollapsed(next)
|
|
79
|
+
if (prefs().rememberCollapsed) {
|
|
80
|
+
void queueTuiPreferenceUpdate(PLUGIN_KEY, ["collapsed"], next).then(() => {
|
|
81
|
+
lastPersistedCollapsed = next
|
|
82
|
+
})
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return { prefs, collapsed, toggleCollapsed }
|
|
87
|
+
}
|
|
88
|
+
|
|
20
89
|
function compactTokens(value: number): string {
|
|
21
90
|
if (value >= 1_000_000) return `${(value / 1_000_000).toFixed(1)}M`
|
|
22
91
|
if (value >= 1_000) return `${(value / 1_000).toFixed(0)}K`
|
|
@@ -325,8 +394,13 @@ const RecompProgressSection = (props: {
|
|
|
325
394
|
case "done":
|
|
326
395
|
return { text: `✓ ${verb()} complete`, color: props.theme.success ?? props.theme.accent }
|
|
327
396
|
case "skipped":
|
|
328
|
-
//
|
|
329
|
-
|
|
397
|
+
// Neutral terse status next to the bold verb header; the full,
|
|
398
|
+
// self-contained reason (lease-busy "try again shortly" vs a
|
|
399
|
+
// partial-stall "run /ctx-embed start again") renders on its own
|
|
400
|
+
// line below. Don't re-prepend verb here (it's already the bold
|
|
401
|
+
// header — doing so read as "EmbedEmbed"), and don't hardcode
|
|
402
|
+
// "retry shortly" (wrong for a partial stall).
|
|
403
|
+
return { text: "stopped", color: props.theme.textMuted }
|
|
330
404
|
case "failed":
|
|
331
405
|
return { text: `✗ ${verb()} failed`, color: props.theme.error }
|
|
332
406
|
}
|
|
@@ -382,12 +456,15 @@ const SidebarContent = (props: {
|
|
|
382
456
|
api: TuiPluginApi
|
|
383
457
|
sessionID: () => string
|
|
384
458
|
theme: TuiThemeCurrent
|
|
459
|
+
controller: SidebarController
|
|
385
460
|
}) => {
|
|
386
461
|
const [snapshot, setSnapshot] = createSignal<SidebarSnapshot | null>(null)
|
|
387
|
-
//
|
|
388
|
-
//
|
|
389
|
-
//
|
|
390
|
-
const
|
|
462
|
+
// Collapse state + section visibility prefs live in the controller (plugin
|
|
463
|
+
// closure), so they survive view-switch remounts and persist across restarts
|
|
464
|
+
// via ~/.config/opencode/tui-preferences.jsonc. Read reactively.
|
|
465
|
+
const collapsed = props.controller.collapsed
|
|
466
|
+
const sections = () => props.controller.prefs().sections
|
|
467
|
+
const headerLabel = () => props.controller.prefs().header.label
|
|
391
468
|
let refreshTimer: ReturnType<typeof setTimeout> | undefined
|
|
392
469
|
// Self-sustaining poll while a recomp/upgrade is running. Recomp work
|
|
393
470
|
// happens in CHILD sessions whose message events are filtered out of the
|
|
@@ -610,11 +687,11 @@ const SidebarContent = (props: {
|
|
|
610
687
|
flexDirection="row"
|
|
611
688
|
justifyContent="space-between"
|
|
612
689
|
alignItems="center"
|
|
613
|
-
onMouseDown={() =>
|
|
690
|
+
onMouseDown={() => props.controller.toggleCollapsed()}
|
|
614
691
|
>
|
|
615
692
|
<box paddingLeft={1} paddingRight={1} backgroundColor={props.theme.accent}>
|
|
616
693
|
<text fg={props.theme.background}>
|
|
617
|
-
<b>{collapsed() ? "▶ " : "▼ "}
|
|
694
|
+
<b>{collapsed() ? "▶ " : "▼ "}{headerLabel()}</b>
|
|
618
695
|
</text>
|
|
619
696
|
</box>
|
|
620
697
|
<text fg={props.theme.textMuted}>v{packageJson.version}</text>
|
|
@@ -688,6 +765,8 @@ const SidebarContent = (props: {
|
|
|
688
765
|
{!collapsed() && (
|
|
689
766
|
<>
|
|
690
767
|
{/* Historian section */}
|
|
768
|
+
{sections().historian && (
|
|
769
|
+
<>
|
|
691
770
|
<box width="100%" marginTop={1} flexDirection="row" justifyContent="space-between">
|
|
692
771
|
<text fg={props.theme.text}>
|
|
693
772
|
<b>Historian</b>
|
|
@@ -713,8 +792,12 @@ const SidebarContent = (props: {
|
|
|
713
792
|
{s()?.recompProgress && (
|
|
714
793
|
<RecompProgressSection theme={props.theme} progress={s()!.recompProgress!} />
|
|
715
794
|
)}
|
|
795
|
+
</>
|
|
796
|
+
)}
|
|
716
797
|
|
|
717
798
|
{/* Memory section */}
|
|
799
|
+
{sections().memory && (
|
|
800
|
+
<>
|
|
718
801
|
<SectionHeader theme={props.theme} title="Memory" />
|
|
719
802
|
<StatRow
|
|
720
803
|
theme={props.theme}
|
|
@@ -730,9 +813,12 @@ const SidebarContent = (props: {
|
|
|
730
813
|
dim
|
|
731
814
|
/>
|
|
732
815
|
)}
|
|
816
|
+
</>
|
|
817
|
+
)}
|
|
733
818
|
|
|
734
819
|
{/* Queue & Status */}
|
|
735
|
-
{(
|
|
820
|
+
{sections().status &&
|
|
821
|
+
((s()?.pendingOpsCount ?? 0) > 0 ||
|
|
736
822
|
(s()?.sessionNoteCount ?? 0) > 0 ||
|
|
737
823
|
(s()?.readySmartNoteCount ?? 0) > 0) && (
|
|
738
824
|
<>
|
|
@@ -764,7 +850,7 @@ const SidebarContent = (props: {
|
|
|
764
850
|
)}
|
|
765
851
|
|
|
766
852
|
{/* Dreamer */}
|
|
767
|
-
{s()?.lastDreamerRunAt && (
|
|
853
|
+
{sections().dreamer && s()?.lastDreamerRunAt && (
|
|
768
854
|
<>
|
|
769
855
|
<SectionHeader theme={props.theme} title="Dreamer" />
|
|
770
856
|
<StatRow
|
|
@@ -782,7 +868,7 @@ const SidebarContent = (props: {
|
|
|
782
868
|
snapshot fields (newWorkTokens, totalInputTokens) and the
|
|
783
869
|
session_meta columns are still populated; only the UI is
|
|
784
870
|
simplified for now. */}
|
|
785
|
-
{s()?.totalInputTokens != null && (
|
|
871
|
+
{sections().stats && s()?.totalInputTokens != null && (
|
|
786
872
|
<>
|
|
787
873
|
<SectionHeader theme={props.theme} title="Stats" />
|
|
788
874
|
<StatRow
|
|
@@ -800,8 +886,15 @@ const SidebarContent = (props: {
|
|
|
800
886
|
}
|
|
801
887
|
|
|
802
888
|
export function createSidebarContentSlot(api: TuiPluginApi): TuiSlotPlugin {
|
|
889
|
+
// Seed synchronously at slot construction so the sidebar renders at its
|
|
890
|
+
// final collapse state + order on the first paint (no async flicker). The
|
|
891
|
+
// controller lives here in the factory closure for the plugin lifetime, so
|
|
892
|
+
// collapse state and live pref reloads survive sidebar_content remounts.
|
|
893
|
+
const seedRoot = readTuiPreferencesFileSync()
|
|
894
|
+
const controller = createSidebarController(resolveMagicContextPrefs(seedRoot))
|
|
895
|
+
const effectiveOrder = computeEffectiveOrder(seedRoot, PLUGIN_KEY, DEFAULT_SLOT_ORDER)
|
|
803
896
|
return {
|
|
804
|
-
order:
|
|
897
|
+
order: effectiveOrder,
|
|
805
898
|
slots: {
|
|
806
899
|
sidebar_content: (ctx, value) => {
|
|
807
900
|
const theme = createMemo(() => ctx.theme.current)
|
|
@@ -810,6 +903,7 @@ export function createSidebarContentSlot(api: TuiPluginApi): TuiSlotPlugin {
|
|
|
810
903
|
api={api}
|
|
811
904
|
sessionID={() => value.session_id}
|
|
812
905
|
theme={theme()}
|
|
906
|
+
controller={controller}
|
|
813
907
|
/>
|
|
814
908
|
)
|
|
815
909
|
},
|