@tarquinen/opencode-dcp 3.2.1-beta0 → 3.2.3-beta0

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.
Files changed (133) hide show
  1. package/README.md +4 -16
  2. package/dist/index.d.ts.map +1 -1
  3. package/dist/index.js +2 -1
  4. package/dist/index.js.map +1 -1
  5. package/dist/lib/commands/compression-targets.d.ts +1 -0
  6. package/dist/lib/commands/compression-targets.d.ts.map +1 -1
  7. package/dist/lib/commands/compression-targets.js +1 -0
  8. package/dist/lib/commands/compression-targets.js.map +1 -1
  9. package/dist/lib/commands/manual.js +1 -1
  10. package/dist/lib/commands/manual.js.map +1 -1
  11. package/dist/lib/commands/stats.d.ts.map +1 -1
  12. package/dist/lib/commands/stats.js +41 -6
  13. package/dist/lib/commands/stats.js.map +1 -1
  14. package/dist/lib/compress/message-utils.d.ts +2 -2
  15. package/dist/lib/compress/message-utils.d.ts.map +1 -1
  16. package/dist/lib/compress/message-utils.js +87 -31
  17. package/dist/lib/compress/message-utils.js.map +1 -1
  18. package/dist/lib/compress/message.d.ts.map +1 -1
  19. package/dist/lib/compress/message.js +10 -6
  20. package/dist/lib/compress/message.js.map +1 -1
  21. package/dist/lib/compress/pipeline.d.ts.map +1 -1
  22. package/dist/lib/compress/pipeline.js +2 -0
  23. package/dist/lib/compress/pipeline.js.map +1 -1
  24. package/dist/lib/compress/range.d.ts.map +1 -1
  25. package/dist/lib/compress/range.js +6 -2
  26. package/dist/lib/compress/range.js.map +1 -1
  27. package/dist/lib/compress/state.d.ts +2 -1
  28. package/dist/lib/compress/state.d.ts.map +1 -1
  29. package/dist/lib/compress/state.js +16 -0
  30. package/dist/lib/compress/state.js.map +1 -1
  31. package/dist/lib/compress/timing.d.ts +18 -0
  32. package/dist/lib/compress/timing.d.ts.map +1 -0
  33. package/dist/lib/compress/timing.js +42 -0
  34. package/dist/lib/compress/timing.js.map +1 -0
  35. package/dist/lib/compress/types.d.ts +2 -0
  36. package/dist/lib/compress/types.d.ts.map +1 -1
  37. package/dist/lib/config.js +1 -1
  38. package/dist/lib/config.js.map +1 -1
  39. package/dist/lib/hooks.d.ts +3 -0
  40. package/dist/lib/hooks.d.ts.map +1 -1
  41. package/dist/lib/hooks.js +72 -2
  42. package/dist/lib/hooks.js.map +1 -1
  43. package/dist/lib/messages/inject/inject.js +2 -2
  44. package/dist/lib/messages/inject/utils.d.ts +0 -1
  45. package/dist/lib/messages/inject/utils.d.ts.map +1 -1
  46. package/dist/lib/messages/inject/utils.js +1 -27
  47. package/dist/lib/messages/inject/utils.js.map +1 -1
  48. package/dist/lib/messages/utils.d.ts +1 -1
  49. package/dist/lib/messages/utils.d.ts.map +1 -1
  50. package/dist/lib/messages/utils.js +5 -12
  51. package/dist/lib/messages/utils.js.map +1 -1
  52. package/dist/lib/prompts/compress-message.d.ts +1 -1
  53. package/dist/lib/prompts/compress-message.d.ts.map +1 -1
  54. package/dist/lib/prompts/compress-message.js +11 -12
  55. package/dist/lib/prompts/compress-message.js.map +1 -1
  56. package/dist/lib/prompts/compress-range.d.ts +1 -1
  57. package/dist/lib/prompts/compress-range.d.ts.map +1 -1
  58. package/dist/lib/prompts/compress-range.js +1 -1
  59. package/dist/lib/prompts/context-limit-nudge.d.ts +1 -1
  60. package/dist/lib/prompts/context-limit-nudge.d.ts.map +1 -1
  61. package/dist/lib/prompts/context-limit-nudge.js +3 -9
  62. package/dist/lib/prompts/context-limit-nudge.js.map +1 -1
  63. package/dist/lib/prompts/extensions/nudge.d.ts +5 -0
  64. package/dist/lib/prompts/extensions/nudge.d.ts.map +1 -0
  65. package/dist/lib/prompts/extensions/nudge.js +35 -0
  66. package/dist/lib/prompts/extensions/nudge.js.map +1 -0
  67. package/dist/lib/prompts/extensions/system.d.ts +4 -0
  68. package/dist/lib/prompts/extensions/system.d.ts.map +1 -0
  69. package/dist/lib/prompts/extensions/system.js +30 -0
  70. package/dist/lib/prompts/extensions/system.js.map +1 -0
  71. package/dist/lib/prompts/extensions/tool.d.ts +3 -0
  72. package/dist/lib/prompts/extensions/tool.d.ts.map +1 -0
  73. package/dist/lib/prompts/extensions/tool.js +34 -0
  74. package/dist/lib/prompts/extensions/tool.js.map +1 -0
  75. package/dist/lib/prompts/index.d.ts +1 -1
  76. package/dist/lib/prompts/index.d.ts.map +1 -1
  77. package/dist/lib/prompts/index.js +12 -13
  78. package/dist/lib/prompts/index.js.map +1 -1
  79. package/dist/lib/prompts/iteration-nudge.d.ts +1 -1
  80. package/dist/lib/prompts/iteration-nudge.d.ts.map +1 -1
  81. package/dist/lib/prompts/iteration-nudge.js +0 -2
  82. package/dist/lib/prompts/iteration-nudge.js.map +1 -1
  83. package/dist/lib/prompts/store.d.ts +2 -2
  84. package/dist/lib/prompts/store.d.ts.map +1 -1
  85. package/dist/lib/prompts/store.js +6 -6
  86. package/dist/lib/prompts/store.js.map +1 -1
  87. package/dist/lib/prompts/system.d.ts +1 -1
  88. package/dist/lib/prompts/system.d.ts.map +1 -1
  89. package/dist/lib/prompts/system.js +0 -13
  90. package/dist/lib/prompts/system.js.map +1 -1
  91. package/dist/lib/prompts/turn-nudge.d.ts +1 -1
  92. package/dist/lib/prompts/turn-nudge.d.ts.map +1 -1
  93. package/dist/lib/prompts/turn-nudge.js +1 -2
  94. package/dist/lib/prompts/turn-nudge.js.map +1 -1
  95. package/dist/lib/state/persistence.d.ts.map +1 -1
  96. package/dist/lib/state/persistence.js +13 -16
  97. package/dist/lib/state/persistence.js.map +1 -1
  98. package/dist/lib/state/state.d.ts.map +1 -1
  99. package/dist/lib/state/state.js +9 -0
  100. package/dist/lib/state/state.js.map +1 -1
  101. package/dist/lib/state/types.d.ts +4 -0
  102. package/dist/lib/state/types.d.ts.map +1 -1
  103. package/dist/lib/state/utils.d.ts +7 -6
  104. package/dist/lib/state/utils.d.ts.map +1 -1
  105. package/dist/lib/state/utils.js +17 -0
  106. package/dist/lib/state/utils.js.map +1 -1
  107. package/lib/analysis/tokens.ts +225 -0
  108. package/lib/config.ts +1071 -0
  109. package/lib/logger.ts +235 -0
  110. package/lib/messages/query.ts +56 -0
  111. package/lib/state/index.ts +4 -0
  112. package/lib/state/persistence.ts +256 -0
  113. package/lib/state/state.ts +190 -0
  114. package/lib/state/tool-cache.ts +98 -0
  115. package/lib/state/types.ts +112 -0
  116. package/lib/state/utils.ts +334 -0
  117. package/lib/token-utils.ts +162 -0
  118. package/package.json +22 -6
  119. package/tui/data/context.ts +177 -0
  120. package/tui/index.tsx +34 -0
  121. package/tui/routes/summary.tsx +175 -0
  122. package/tui/shared/names.ts +9 -0
  123. package/tui/shared/theme.ts +58 -0
  124. package/tui/shared/types.ts +38 -0
  125. package/tui/slots/sidebar-content.tsx +502 -0
  126. package/dist/lib/prompts/internal-overlays.d.ts +0 -5
  127. package/dist/lib/prompts/internal-overlays.d.ts.map +0 -1
  128. package/dist/lib/prompts/internal-overlays.js +0 -49
  129. package/dist/lib/prompts/internal-overlays.js.map +0 -1
  130. package/dist/lib/prompts/message-priority-guidance.d.ts +0 -2
  131. package/dist/lib/prompts/message-priority-guidance.d.ts.map +0 -1
  132. package/dist/lib/prompts/message-priority-guidance.js +0 -9
  133. package/dist/lib/prompts/message-priority-guidance.js.map +0 -1
@@ -0,0 +1,502 @@
1
+ /** @jsxImportSource @opentui/solid */
2
+ import { createEffect, createMemo, createSignal, on, onCleanup, untrack } from "solid-js"
3
+ import type { TuiSlotPlugin } from "@opencode-ai/plugin/tui"
4
+ import { Logger } from "../../lib/logger"
5
+ import {
6
+ createPlaceholderContextSnapshot,
7
+ invalidateContextSnapshot,
8
+ loadContextSnapshotCached,
9
+ peekContextSnapshot,
10
+ } from "../data/context"
11
+ import { getPalette, toneColor, type DcpColor, type DcpPalette } from "../shared/theme"
12
+ import { LABEL, type DcpRouteNames } from "../shared/names"
13
+ import type { DcpActiveBlockInfo, DcpMessageStatus, DcpTuiApi } from "../shared/types"
14
+
15
+ const SINGLE_BORDER = { type: "single" } as any
16
+ const DIM_TEXT = { dim: true } as any
17
+
18
+ const REFRESH_DEBOUNCE_MS = 100
19
+ const MAX_TOPIC_LEN = 30
20
+
21
+ const truncateTopic = (topic: string): string =>
22
+ topic.length > MAX_TOPIC_LEN ? topic.slice(0, MAX_TOPIC_LEN - 3) + "..." : topic
23
+
24
+ const compactTokenCount = (value: number): string => {
25
+ if (value >= 1_000_000) {
26
+ const m = (value / 1_000_000).toFixed(2)
27
+ return `${m}M`
28
+ }
29
+ if (value >= 100_000) return `${Math.round(value / 1000)}K`
30
+ if (value >= 1_000) {
31
+ const k = (value / 1000).toFixed(1)
32
+ return k.endsWith(".0") ? `${Math.round(value / 1000)}K` : `${k}K`
33
+ }
34
+ const d = Math.round(value / 100)
35
+ if (d >= 10) return `${Math.round(value / 1000)}K`
36
+ if (d > 0) return `.${d}K`
37
+ return "0"
38
+ }
39
+
40
+ const buildMessageRuns = (
41
+ statuses: DcpMessageStatus[],
42
+ ): { count: number; status: DcpMessageStatus }[] => {
43
+ if (statuses.length === 0) return []
44
+
45
+ // Group consecutive same-status messages into runs
46
+ const runs: { count: number; status: DcpMessageStatus }[] = []
47
+ let runStart = 0
48
+ for (let i = 1; i <= statuses.length; i++) {
49
+ if (i === statuses.length || statuses[i] !== statuses[runStart]) {
50
+ runs.push({ count: i - runStart, status: statuses[runStart] })
51
+ runStart = i
52
+ }
53
+ }
54
+ return runs
55
+ }
56
+
57
+ const SummaryRow = (props: {
58
+ palette: DcpPalette
59
+ label: string
60
+ value: string
61
+ tone?: "text" | "muted" | "accent" | "success" | "warning"
62
+ swatch?: DcpColor
63
+ marginTop?: number
64
+ }) => {
65
+ return (
66
+ <box
67
+ width="100%"
68
+ flexDirection="row"
69
+ justifyContent="space-between"
70
+ marginTop={props.marginTop}
71
+ >
72
+ <box flexDirection="row">
73
+ {props.swatch && <text fg={props.swatch}>{"█ "}</text>}
74
+ <text fg={props.palette.text}>{props.label}</text>
75
+ </box>
76
+ <text fg={toneColor(props.palette, props.tone)}>
77
+ <b>{props.value}</b>
78
+ </text>
79
+ </box>
80
+ )
81
+ }
82
+
83
+ const SidebarContextBar = (props: {
84
+ palette: DcpPalette
85
+ label: string
86
+ value: number
87
+ total: number
88
+ tone?: "text" | "muted" | "accent" | "success" | "warning"
89
+ }) => {
90
+ const percent = createMemo(() =>
91
+ props.total > 0 ? `${Math.round((props.value / props.total) * 100)}%` : "0%",
92
+ )
93
+ const label = createMemo(() => props.label.padEnd(9, " "))
94
+ return (
95
+ <box width="100%" flexDirection="row">
96
+ <text fg={props.palette.text}>
97
+ {label()}
98
+ {` ${percent().padStart(4, " ")} |`}
99
+ </text>
100
+ <box flexGrow={1} flexDirection="row" height={1}>
101
+ {props.value > 0 && (
102
+ <box
103
+ flexGrow={props.value}
104
+ backgroundColor={toneColor(props.palette, props.tone)}
105
+ />
106
+ )}
107
+ {props.total > props.value && <box flexGrow={props.total - props.value} />}
108
+ </box>
109
+ <text fg={props.palette.text}>
110
+ {`| ${compactTokenCount(props.value).padStart(5, " ")}`}
111
+ </text>
112
+ </box>
113
+ )
114
+ }
115
+
116
+ const SidebarContext = (props: {
117
+ api: DcpTuiApi
118
+ names: DcpRouteNames
119
+ palette: DcpPalette
120
+ sessionID: () => string
121
+ logger: Logger
122
+ }) => {
123
+ const initialSnapshot = peekContextSnapshot(props.sessionID())
124
+ const [snapshot, setSnapshot] = createSignal(
125
+ initialSnapshot ?? createPlaceholderContextSnapshot(props.sessionID()),
126
+ )
127
+ const [loading, setLoading] = createSignal(!initialSnapshot)
128
+ const [error, setError] = createSignal<string>()
129
+ let requestVersion = 0
130
+ let renderTimeout: ReturnType<typeof setTimeout> | undefined
131
+
132
+ const requestRender = () => {
133
+ if (renderTimeout) clearTimeout(renderTimeout)
134
+ renderTimeout = setTimeout(() => {
135
+ renderTimeout = undefined
136
+ try {
137
+ props.api.renderer.requestRender()
138
+ } catch (error) {
139
+ props.logger.warn("Failed to request TUI render", {
140
+ error: error instanceof Error ? error.message : String(error),
141
+ })
142
+ }
143
+ }, 0)
144
+ }
145
+
146
+ onCleanup(() => {
147
+ if (renderTimeout) clearTimeout(renderTimeout)
148
+ })
149
+
150
+ const refreshSnapshot = async (
151
+ sessionID: string,
152
+ options?: { invalidate?: boolean; preserveSnapshot?: boolean },
153
+ ) => {
154
+ if (options?.invalidate) {
155
+ invalidateContextSnapshot(sessionID)
156
+ }
157
+
158
+ const cached = peekContextSnapshot(sessionID)
159
+ let silentRefresh = false
160
+ if (cached) {
161
+ setSnapshot(cached)
162
+ setLoading(false)
163
+ } else {
164
+ const current = untrack(snapshot)
165
+ if (options?.preserveSnapshot && current?.sessionID === sessionID) {
166
+ silentRefresh = true
167
+ } else {
168
+ setSnapshot(createPlaceholderContextSnapshot(sessionID, ["Loading DCP context..."]))
169
+ setLoading(true)
170
+ }
171
+ }
172
+ setError(undefined)
173
+ if (!silentRefresh) {
174
+ requestRender()
175
+ }
176
+
177
+ const currentRequest = ++requestVersion
178
+
179
+ try {
180
+ const value = await loadContextSnapshotCached(props.api.client, props.logger, sessionID)
181
+ if (currentRequest !== requestVersion || props.sessionID() !== sessionID) {
182
+ return
183
+ }
184
+ setSnapshot(value)
185
+ setLoading(false)
186
+ requestRender()
187
+ } catch (cause) {
188
+ if (currentRequest !== requestVersion || props.sessionID() !== sessionID) {
189
+ return
190
+ }
191
+ props.logger.warn("Failed to refresh sidebar snapshot", {
192
+ sessionID,
193
+ error: cause instanceof Error ? cause.message : String(cause),
194
+ })
195
+ setError(cause instanceof Error ? cause.message : String(cause))
196
+ setLoading(false)
197
+ requestRender()
198
+ }
199
+ }
200
+
201
+ createEffect(
202
+ on(
203
+ props.sessionID,
204
+ (sessionID) => {
205
+ void refreshSnapshot(sessionID)
206
+ },
207
+ { defer: false },
208
+ ),
209
+ )
210
+
211
+ createEffect(
212
+ on(
213
+ props.sessionID,
214
+ (sessionID) => {
215
+ let timeout: ReturnType<typeof setTimeout> | undefined
216
+
217
+ const scheduleRefresh = () => {
218
+ if (!sessionID) return
219
+ if (timeout) clearTimeout(timeout)
220
+ timeout = setTimeout(() => {
221
+ timeout = undefined
222
+ void refreshSnapshot(sessionID, {
223
+ invalidate: true,
224
+ preserveSnapshot: true,
225
+ })
226
+ }, REFRESH_DEBOUNCE_MS)
227
+ }
228
+
229
+ const unsubs = [
230
+ props.api.event.on("message.updated", (event) => {
231
+ if (event.properties.info.sessionID !== sessionID) return
232
+ scheduleRefresh()
233
+ }),
234
+ props.api.event.on("message.removed", (event) => {
235
+ if (event.properties.sessionID !== sessionID) return
236
+ scheduleRefresh()
237
+ }),
238
+ props.api.event.on("message.part.updated", (event) => {
239
+ if (event.properties.part.sessionID !== sessionID) return
240
+ scheduleRefresh()
241
+ }),
242
+ props.api.event.on("message.part.delta", (event) => {
243
+ if (event.properties.sessionID !== sessionID) return
244
+ scheduleRefresh()
245
+ }),
246
+ props.api.event.on("message.part.removed", (event) => {
247
+ if (event.properties.sessionID !== sessionID) return
248
+ scheduleRefresh()
249
+ }),
250
+ props.api.event.on("session.updated", (event) => {
251
+ if (event.properties.info.id !== sessionID) return
252
+ scheduleRefresh()
253
+ }),
254
+ props.api.event.on("session.deleted", (event) => {
255
+ if (event.properties.info.id !== sessionID) return
256
+ scheduleRefresh()
257
+ }),
258
+ props.api.event.on("session.diff", (event) => {
259
+ if (event.properties.sessionID !== sessionID) return
260
+ scheduleRefresh()
261
+ }),
262
+ props.api.event.on("session.error", (event) => {
263
+ if (event.properties.sessionID !== sessionID) return
264
+ scheduleRefresh()
265
+ }),
266
+ props.api.event.on("session.status", (event) => {
267
+ if (event.properties.sessionID !== sessionID) return
268
+ scheduleRefresh()
269
+ }),
270
+ ]
271
+
272
+ onCleanup(() => {
273
+ if (timeout) clearTimeout(timeout)
274
+ for (const unsub of unsubs) {
275
+ unsub()
276
+ }
277
+ })
278
+ },
279
+ { defer: false },
280
+ ),
281
+ )
282
+
283
+ const TOPIC_LIMIT = 3
284
+ const allBlocks = createMemo(() => snapshot().persisted.activeBlocks)
285
+ const [topicsExpanded, setTopicsExpanded] = createSignal(false)
286
+ const blocks = createMemo(() =>
287
+ topicsExpanded() ? allBlocks() : allBlocks().slice(0, TOPIC_LIMIT),
288
+ )
289
+ const topicOverflow = createMemo(() => allBlocks().length - TOPIC_LIMIT)
290
+
291
+ const navigateToSummary = (block: DcpActiveBlockInfo) => {
292
+ props.api.route.navigate(props.names.routes.summary, {
293
+ topic: block.topic,
294
+ summary: block.summary,
295
+ sessionID: props.sessionID(),
296
+ })
297
+ }
298
+ const fallbackNote = createMemo(() => snapshot().notes[0] ?? "")
299
+
300
+ const messageBarRuns = createMemo(() => buildMessageRuns(snapshot().messageStatuses))
301
+
302
+ const status = createMemo(() => {
303
+ if (error() && snapshot().breakdown.total > 0)
304
+ return { label: "cached", tone: "warning" as const }
305
+ if (error()) return { label: "error", tone: "warning" as const }
306
+ if (loading() && snapshot().breakdown.total > 0)
307
+ return { label: "refreshing", tone: "warning" as const }
308
+ if (loading()) return { label: "loading", tone: "warning" as const }
309
+ return { label: "loaded", tone: "success" as const }
310
+ })
311
+
312
+ return (
313
+ <box
314
+ width="100%"
315
+ flexDirection="column"
316
+ backgroundColor={props.palette.surface}
317
+ border={SINGLE_BORDER}
318
+ borderColor={props.palette.accent}
319
+ paddingTop={1}
320
+ paddingBottom={1}
321
+ paddingLeft={1}
322
+ paddingRight={1}
323
+ >
324
+ <box flexDirection="row" justifyContent="space-between" alignItems="center">
325
+ <box flexDirection="row" gap={1} alignItems="center">
326
+ <box paddingLeft={1} paddingRight={1} backgroundColor={props.palette.accent}>
327
+ <text fg={props.palette.panel}>
328
+ <b>{LABEL}</b>
329
+ </text>
330
+ </box>
331
+ </box>
332
+ <text fg={toneColor(props.palette, status().tone)}>{status().label}</text>
333
+ </box>
334
+
335
+ <SummaryRow
336
+ palette={props.palette}
337
+ label="Current Messages"
338
+ value={`~${compactTokenCount(snapshot().breakdown.total)}`}
339
+ tone="accent"
340
+ swatch={props.palette.accent}
341
+ marginTop={1}
342
+ />
343
+ <SummaryRow
344
+ palette={props.palette}
345
+ label="Compressed Messages"
346
+ value={`~${compactTokenCount(snapshot().breakdown.prunedTokens)}`}
347
+ tone="accent"
348
+ swatch={props.palette.muted}
349
+ />
350
+
351
+ {snapshot().messageStatuses.length > 0 && (
352
+ <box width="100%" flexDirection="row" height={1} marginTop={1}>
353
+ {messageBarRuns().map((run) => (
354
+ <box
355
+ flexGrow={run.count}
356
+ backgroundColor={
357
+ run.status === "active" ? props.palette.accent : props.palette.muted
358
+ }
359
+ />
360
+ ))}
361
+ </box>
362
+ )}
363
+
364
+ <box width="100%" flexDirection="column" paddingTop={1}>
365
+ <SidebarContextBar
366
+ palette={props.palette}
367
+ label="System"
368
+ value={snapshot().breakdown.system}
369
+ total={snapshot().breakdown.total}
370
+ tone="accent"
371
+ />
372
+ <SidebarContextBar
373
+ palette={props.palette}
374
+ label="User"
375
+ value={snapshot().breakdown.user}
376
+ total={snapshot().breakdown.total}
377
+ tone="accent"
378
+ />
379
+ <SidebarContextBar
380
+ palette={props.palette}
381
+ label="Assistant"
382
+ value={snapshot().breakdown.assistant}
383
+ total={snapshot().breakdown.total}
384
+ tone="accent"
385
+ />
386
+ <SidebarContextBar
387
+ palette={props.palette}
388
+ label="Tools"
389
+ value={snapshot().breakdown.tools}
390
+ total={snapshot().breakdown.total}
391
+ tone="accent"
392
+ />
393
+ </box>
394
+
395
+ <box width="100%" flexDirection="column" gap={0} paddingTop={1}>
396
+ {blocks().length > 0 ? (
397
+ <>
398
+ <box width="100%" flexDirection="row" justifyContent="space-between">
399
+ <text fg={props.palette.text}>
400
+ <b>Compressed Summaries</b>
401
+ </text>
402
+ <text fg={toneColor(props.palette, "accent")}>
403
+ <b>{`~${compactTokenCount(snapshot().activeSummaryTokens)}`}</b>
404
+ </text>
405
+ </box>
406
+ {blocks().map((block) => (
407
+ <box flexDirection="row" width="100%" height={1}>
408
+ <box flexGrow={1} flexShrink={1} overflow="hidden" height={1}>
409
+ <text fg={props.palette.muted}>
410
+ {truncateTopic(block.topic)}
411
+ </text>
412
+ </box>
413
+ <box flexShrink={0} height={1} paddingLeft={1}>
414
+ <box
415
+ backgroundColor={props.palette.base}
416
+ height={1}
417
+ onMouseUp={() => navigateToSummary(block)}
418
+ >
419
+ <text fg={props.palette.accent}> ▶ </text>
420
+ </box>
421
+ </box>
422
+ </box>
423
+ ))}
424
+ {topicOverflow() > 0 ? (
425
+ <box flexDirection="row" width="100%" height={1}>
426
+ <box flexGrow={1} flexShrink={1} height={1}>
427
+ <text {...DIM_TEXT} fg={props.palette.muted}>
428
+ {topicsExpanded()
429
+ ? `showing all ${allBlocks().length} topics`
430
+ : `... ${topicOverflow()} more topics`}
431
+ </text>
432
+ </box>
433
+ <box flexShrink={0} height={1} paddingLeft={1}>
434
+ <box
435
+ backgroundColor={props.palette.base}
436
+ height={1}
437
+ onMouseUp={() => setTopicsExpanded(!topicsExpanded())}
438
+ >
439
+ <text fg={props.palette.accent}>
440
+ {topicsExpanded() ? " ▲ " : " ▼ "}
441
+ </text>
442
+ </box>
443
+ </box>
444
+ </box>
445
+ ) : null}
446
+ </>
447
+ ) : fallbackNote() ? (
448
+ <text fg={props.palette.muted}>{fallbackNote()}</text>
449
+ ) : null}
450
+ </box>
451
+
452
+ {snapshot().allTimeStats.sessionCount > 0 && (
453
+ <box width="100%" flexDirection="column" paddingTop={1}>
454
+ <text fg={props.palette.text}>
455
+ <b>All Time</b>
456
+ </text>
457
+ <SummaryRow
458
+ palette={props.palette}
459
+ label="Tokens Saved"
460
+ value={`~${compactTokenCount(snapshot().allTimeStats.totalTokensSaved)}`}
461
+ tone="accent"
462
+ />
463
+ <SummaryRow
464
+ palette={props.palette}
465
+ label="Sessions"
466
+ value={`${snapshot().allTimeStats.sessionCount}`}
467
+ tone="accent"
468
+ />
469
+ </box>
470
+ )}
471
+ </box>
472
+ )
473
+ }
474
+
475
+ export const createSidebarContentSlot = (
476
+ api: DcpTuiApi,
477
+ names: DcpRouteNames,
478
+ logger: Logger,
479
+ ): TuiSlotPlugin => {
480
+ const renderSidebar = (
481
+ ctx: { theme: { current: Record<string, unknown> } },
482
+ value: { session_id: string },
483
+ ) => {
484
+ const palette = createMemo(() => getPalette(ctx.theme.current as Record<string, unknown>))
485
+ return (
486
+ <SidebarContext
487
+ api={api}
488
+ names={names}
489
+ palette={palette()}
490
+ sessionID={() => value.session_id}
491
+ logger={logger}
492
+ />
493
+ )
494
+ }
495
+
496
+ return {
497
+ order: 90,
498
+ slots: {
499
+ sidebar_content: renderSidebar,
500
+ },
501
+ }
502
+ }
@@ -1,5 +0,0 @@
1
- export declare const MANUAL_MODE_SYSTEM_OVERLAY = "<dcp-system-reminder>\nManual mode is enabled. Do NOT use compress unless the user has explicitly triggered it through a manual marker.\n\nOnly use the compress tool after seeing `<compress triggered manually>` in the current user instruction context.\n\nIssue exactly ONE compress call per manual trigger. Do NOT launch multiple compress calls in parallel. Each trigger grants a single compression; after it completes, wait for the next trigger.\n\nAfter completing a manually triggered context-management action, STOP IMMEDIATELY. Do NOT continue with any task execution. End your response right after the tool use completes and wait for the next user input.\n</dcp-system-reminder>\n";
2
- export declare const SUBAGENT_SYSTEM_OVERLAY = "<dcp-system-reminder>\nYou are operating in a subagent environment.\n\nThe initial subagent instruction is imperative and must be followed exactly.\nIt is the only user message intentionally not assigned a message ID, and therefore is not eligible for compression.\nAll subsequent messages in the session will have IDs.\n</dcp-system-reminder>\n";
3
- export declare const RANGE_FORMAT_OVERLAY = "\nTHE FORMAT OF COMPRESS\n\n```\n{\n topic: string, // Short label (3-5 words) - e.g., \"Auth System Exploration\"\n content: [ // One or more ranges to compress\n {\n startId: string, // Boundary ID at range start: mNNNN or bN\n endId: string, // Boundary ID at range end: mNNNN or bN\n summary: string // Complete technical summary replacing all content in range\n }\n ]\n}\n```";
4
- export declare const MESSAGE_FORMAT_OVERLAY = "\nTHE FORMAT OF COMPRESS\n\n```\n{\n topic: string, // Short label (3-5 words) for the overall batch\n content: [ // One or more messages to compress independently\n {\n messageId: string, // Raw message ID only: mNNNN (ignore metadata attributes like priority)\n topic: string, // Short label (3-5 words) for this one message summary\n summary: string // Complete technical summary replacing that one message\n }\n ]\n}\n```";
5
- //# sourceMappingURL=internal-overlays.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"internal-overlays.d.ts","sourceRoot":"","sources":["../../../lib/prompts/internal-overlays.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,0BAA0B,mrBAStC,CAAA;AAED,eAAO,MAAM,uBAAuB,8VAOnC,CAAA;AAED,eAAO,MAAM,oBAAoB,gcAc1B,CAAA;AAEP,eAAO,MAAM,sBAAsB,2eAc5B,CAAA"}
@@ -1,49 +0,0 @@
1
- export const MANUAL_MODE_SYSTEM_OVERLAY = `<dcp-system-reminder>
2
- Manual mode is enabled. Do NOT use compress unless the user has explicitly triggered it through a manual marker.
3
-
4
- Only use the compress tool after seeing \`<compress triggered manually>\` in the current user instruction context.
5
-
6
- Issue exactly ONE compress call per manual trigger. Do NOT launch multiple compress calls in parallel. Each trigger grants a single compression; after it completes, wait for the next trigger.
7
-
8
- After completing a manually triggered context-management action, STOP IMMEDIATELY. Do NOT continue with any task execution. End your response right after the tool use completes and wait for the next user input.
9
- </dcp-system-reminder>
10
- `;
11
- export const SUBAGENT_SYSTEM_OVERLAY = `<dcp-system-reminder>
12
- You are operating in a subagent environment.
13
-
14
- The initial subagent instruction is imperative and must be followed exactly.
15
- It is the only user message intentionally not assigned a message ID, and therefore is not eligible for compression.
16
- All subsequent messages in the session will have IDs.
17
- </dcp-system-reminder>
18
- `;
19
- export const RANGE_FORMAT_OVERLAY = `
20
- THE FORMAT OF COMPRESS
21
-
22
- \`\`\`
23
- {
24
- topic: string, // Short label (3-5 words) - e.g., "Auth System Exploration"
25
- content: [ // One or more ranges to compress
26
- {
27
- startId: string, // Boundary ID at range start: mNNNN or bN
28
- endId: string, // Boundary ID at range end: mNNNN or bN
29
- summary: string // Complete technical summary replacing all content in range
30
- }
31
- ]
32
- }
33
- \`\`\``;
34
- export const MESSAGE_FORMAT_OVERLAY = `
35
- THE FORMAT OF COMPRESS
36
-
37
- \`\`\`
38
- {
39
- topic: string, // Short label (3-5 words) for the overall batch
40
- content: [ // One or more messages to compress independently
41
- {
42
- messageId: string, // Raw message ID only: mNNNN (ignore metadata attributes like priority)
43
- topic: string, // Short label (3-5 words) for this one message summary
44
- summary: string // Complete technical summary replacing that one message
45
- }
46
- ]
47
- }
48
- \`\`\``;
49
- //# sourceMappingURL=internal-overlays.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"internal-overlays.js","sourceRoot":"","sources":["../../../lib/prompts/internal-overlays.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,0BAA0B,GAAG;;;;;;;;;CASzC,CAAA;AAED,MAAM,CAAC,MAAM,uBAAuB,GAAG;;;;;;;CAOtC,CAAA;AAED,MAAM,CAAC,MAAM,oBAAoB,GAAG;;;;;;;;;;;;;;OAc7B,CAAA;AAEP,MAAM,CAAC,MAAM,sBAAsB,GAAG;;;;;;;;;;;;;;OAc/B,CAAA"}
@@ -1,2 +0,0 @@
1
- export declare function renderMessagePriorityGuidance(priorityLabel: string, refs: string[]): string;
2
- //# sourceMappingURL=message-priority-guidance.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"message-priority-guidance.d.ts","sourceRoot":"","sources":["../../../lib/prompts/message-priority-guidance.ts"],"names":[],"mappings":"AAAA,wBAAgB,6BAA6B,CAAC,aAAa,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,MAAM,CAQ3F"}
@@ -1,9 +0,0 @@
1
- export function renderMessagePriorityGuidance(priorityLabel, refs) {
2
- const refList = refs.length > 0 ? refs.join(", ") : "none";
3
- return [
4
- "Message priority context:",
5
- "- Higher-priority older messages consume more context and should be compressed before lower-priority ones when safely closed.",
6
- `- ${priorityLabel}-priority message IDs before this point: ${refList}`,
7
- ].join("\n");
8
- }
9
- //# sourceMappingURL=message-priority-guidance.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"message-priority-guidance.js","sourceRoot":"","sources":["../../../lib/prompts/message-priority-guidance.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,6BAA6B,CAAC,aAAqB,EAAE,IAAc;IAC/E,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,CAAA;IAE1D,OAAO;QACH,2BAA2B;QAC3B,+HAA+H;QAC/H,KAAK,aAAa,4CAA4C,OAAO,EAAE;KAC1E,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AAChB,CAAC"}